2024-08-04 23:09:29 -05:00
|
|
|
# -*- coding: utf-8; -*-
|
|
|
|
|
2024-08-14 18:29:08 -05:00
|
|
|
from unittest.mock import MagicMock, patch
|
2024-08-04 23:09:29 -05:00
|
|
|
|
2024-08-05 14:21:54 -05:00
|
|
|
from pyramid.httpexceptions import HTTPFound, HTTPForbidden
|
2024-08-04 23:09:29 -05:00
|
|
|
|
|
|
|
from wuttaweb.views import auth as mod
|
2024-08-14 18:29:08 -05:00
|
|
|
from tests.util import WebTestCase
|
2024-08-04 23:09:29 -05:00
|
|
|
|
|
|
|
|
2024-08-14 18:29:08 -05:00
|
|
|
class TestAuthView(WebTestCase):
|
2024-08-04 23:09:29 -05:00
|
|
|
|
|
|
|
def setUp(self):
|
2024-08-14 18:29:08 -05:00
|
|
|
self.setup_web()
|
|
|
|
self.pyramid_config.include('wuttaweb.views.common')
|
2024-08-04 23:09:29 -05:00
|
|
|
|
2024-08-14 18:29:08 -05:00
|
|
|
def make_view(self):
|
|
|
|
return mod.AuthView(self.request)
|
2024-08-04 23:09:29 -05:00
|
|
|
|
2024-08-14 18:29:08 -05:00
|
|
|
def test_includeme(self):
|
|
|
|
self.pyramid_config.include('wuttaweb.views.auth')
|
|
|
|
|
|
|
|
def test_login(self):
|
2024-08-04 23:09:29 -05:00
|
|
|
model = self.app.model
|
2024-08-14 18:29:08 -05:00
|
|
|
auth = self.app.get_auth_handler()
|
|
|
|
view = self.make_view()
|
2024-08-04 23:09:29 -05:00
|
|
|
|
2024-08-14 18:29:08 -05:00
|
|
|
# until user exists, will redirect
|
|
|
|
self.assertEqual(self.session.query(model.User).count(), 0)
|
|
|
|
response = view.login(session=self.session)
|
|
|
|
self.assertEqual(response.status_code, 302)
|
2024-08-04 23:09:29 -05:00
|
|
|
|
2024-08-14 18:29:08 -05:00
|
|
|
# make a user
|
|
|
|
barney = model.User(username='barney')
|
|
|
|
auth.set_user_password(barney, 'testpass')
|
|
|
|
self.session.add(barney)
|
|
|
|
self.session.commit()
|
2024-08-04 23:09:29 -05:00
|
|
|
|
2024-08-14 18:29:08 -05:00
|
|
|
# now since user exists, form will display
|
|
|
|
context = view.login(session=self.session)
|
2024-08-04 23:09:29 -05:00
|
|
|
self.assertIn('form', context)
|
|
|
|
|
|
|
|
# redirect if user already logged in
|
2024-08-14 18:29:08 -05:00
|
|
|
with patch.object(self.request, 'user', new=barney):
|
|
|
|
view = self.make_view()
|
|
|
|
response = view.login(session=self.session)
|
|
|
|
self.assertEqual(response.status_code, 302)
|
2024-08-04 23:09:29 -05:00
|
|
|
|
|
|
|
# login fails w/ wrong password
|
|
|
|
self.request.method = 'POST'
|
|
|
|
self.request.POST = {'username': 'barney', 'password': 'WRONG'}
|
2024-08-14 18:29:08 -05:00
|
|
|
view = self.make_view()
|
2024-08-04 23:09:29 -05:00
|
|
|
context = view.login(session=self.session)
|
|
|
|
self.assertIn('form', context)
|
|
|
|
|
|
|
|
# redirect if login succeeds
|
|
|
|
self.request.method = 'POST'
|
|
|
|
self.request.POST = {'username': 'barney', 'password': 'testpass'}
|
2024-08-14 18:29:08 -05:00
|
|
|
view = self.make_view()
|
|
|
|
response = view.login(session=self.session)
|
|
|
|
self.assertEqual(response.status_code, 302)
|
2024-08-04 23:09:29 -05:00
|
|
|
|
|
|
|
def test_logout(self):
|
2024-08-14 18:29:08 -05:00
|
|
|
self.pyramid_config.add_route('login', '/login')
|
|
|
|
view = self.make_view()
|
2024-08-04 23:09:29 -05:00
|
|
|
self.request.session.delete = MagicMock()
|
2024-08-14 18:29:08 -05:00
|
|
|
response = view.logout()
|
2024-08-04 23:09:29 -05:00
|
|
|
self.request.session.delete.assert_called_once_with()
|
2024-08-14 18:29:08 -05:00
|
|
|
self.assertEqual(response.status_code, 302)
|
2024-08-05 11:45:00 -05:00
|
|
|
|
|
|
|
def test_change_password(self):
|
2024-08-14 18:29:08 -05:00
|
|
|
model = self.app.model
|
2024-08-05 11:45:00 -05:00
|
|
|
auth = self.app.get_auth_handler()
|
2024-08-14 18:29:08 -05:00
|
|
|
barney = model.User(username='barney')
|
|
|
|
self.session.add(barney)
|
|
|
|
self.session.commit()
|
|
|
|
view = self.make_view()
|
2024-08-05 11:45:00 -05:00
|
|
|
|
|
|
|
# unauthenticated user is redirected
|
|
|
|
redirect = view.change_password()
|
|
|
|
self.assertIsInstance(redirect, HTTPFound)
|
|
|
|
|
|
|
|
# now "login" the user, and set initial password
|
2024-08-14 18:29:08 -05:00
|
|
|
self.request.user = barney
|
|
|
|
auth.set_user_password(barney, 'foo')
|
2024-08-05 11:45:00 -05:00
|
|
|
self.session.commit()
|
|
|
|
|
|
|
|
# view should now return context w/ form
|
|
|
|
context = view.change_password()
|
|
|
|
self.assertIn('form', context)
|
|
|
|
|
|
|
|
# submit valid form, ensure password is changed
|
|
|
|
# (nb. this also would redirect user to home page)
|
|
|
|
self.request.method = 'POST'
|
|
|
|
self.request.POST = {
|
|
|
|
'current_password': 'foo',
|
|
|
|
# nb. new_password requires colander mapping structure
|
|
|
|
'__start__': 'new_password:mapping',
|
|
|
|
'new_password': 'bar',
|
|
|
|
'new_password-confirm': 'bar',
|
|
|
|
'__end__': 'new_password:mapping',
|
|
|
|
}
|
|
|
|
redirect = view.change_password()
|
|
|
|
self.assertIsInstance(redirect, HTTPFound)
|
|
|
|
self.session.commit()
|
2024-08-14 18:29:08 -05:00
|
|
|
self.assertFalse(auth.check_user_password(barney, 'foo'))
|
|
|
|
self.assertTrue(auth.check_user_password(barney, 'bar'))
|
2024-08-05 11:45:00 -05:00
|
|
|
|
|
|
|
# at this point 'foo' is the password, now let's submit some
|
|
|
|
# invalid forms and make sure we get back a context w/ form
|
|
|
|
|
|
|
|
# first try empty data
|
|
|
|
self.request.POST = {}
|
|
|
|
context = view.change_password()
|
|
|
|
self.assertIn('form', context)
|
|
|
|
dform = context['form'].get_deform()
|
|
|
|
self.assertEqual(dform['current_password'].errormsg, "Required")
|
|
|
|
self.assertEqual(dform['new_password'].errormsg, "Required")
|
|
|
|
|
|
|
|
# now try bad current password
|
|
|
|
self.request.POST = {
|
|
|
|
'current_password': 'blahblah',
|
|
|
|
'__start__': 'new_password:mapping',
|
|
|
|
'new_password': 'baz',
|
|
|
|
'new_password-confirm': 'baz',
|
|
|
|
'__end__': 'new_password:mapping',
|
|
|
|
}
|
|
|
|
context = view.change_password()
|
|
|
|
self.assertIn('form', context)
|
|
|
|
dform = context['form'].get_deform()
|
|
|
|
self.assertEqual(dform['current_password'].errormsg, "Current password is incorrect.")
|
|
|
|
|
|
|
|
# now try bad new password
|
|
|
|
self.request.POST = {
|
|
|
|
'current_password': 'bar',
|
|
|
|
'__start__': 'new_password:mapping',
|
|
|
|
'new_password': 'bar',
|
|
|
|
'new_password-confirm': 'bar',
|
|
|
|
'__end__': 'new_password:mapping',
|
|
|
|
}
|
|
|
|
context = view.change_password()
|
|
|
|
self.assertIn('form', context)
|
|
|
|
dform = context['form'].get_deform()
|
|
|
|
self.assertEqual(dform['new_password'].errormsg, "New password must be different from old password.")
|
2024-08-05 14:21:54 -05:00
|
|
|
|
|
|
|
def test_become_root(self):
|
|
|
|
view = mod.AuthView(self.request)
|
|
|
|
|
|
|
|
# GET not allowed
|
|
|
|
self.request.method = 'GET'
|
|
|
|
self.assertRaises(HTTPForbidden, view.become_root)
|
|
|
|
|
|
|
|
# non-admin users also not allowed
|
|
|
|
self.request.method = 'POST'
|
|
|
|
self.request.is_admin = False
|
|
|
|
self.assertRaises(HTTPForbidden, view.become_root)
|
|
|
|
|
|
|
|
# but admin users can become root
|
|
|
|
self.request.is_admin = True
|
|
|
|
self.assertNotIn('is_root', self.request.session)
|
|
|
|
redirect = view.become_root()
|
|
|
|
self.assertIsInstance(redirect, HTTPFound)
|
|
|
|
self.assertTrue(self.request.session['is_root'])
|
|
|
|
|
|
|
|
def test_stop_root(self):
|
|
|
|
view = mod.AuthView(self.request)
|
|
|
|
|
|
|
|
# GET not allowed
|
|
|
|
self.request.method = 'GET'
|
|
|
|
self.assertRaises(HTTPForbidden, view.stop_root)
|
|
|
|
|
|
|
|
# non-admin users also not allowed
|
|
|
|
self.request.method = 'POST'
|
|
|
|
self.request.is_admin = False
|
|
|
|
self.assertRaises(HTTPForbidden, view.stop_root)
|
|
|
|
|
|
|
|
# but admin users can stop being root
|
|
|
|
# (nb. there is no check whether user is currently root)
|
|
|
|
self.request.is_admin = True
|
|
|
|
self.assertNotIn('is_root', self.request.session)
|
|
|
|
redirect = view.stop_root()
|
|
|
|
self.assertIsInstance(redirect, HTTPFound)
|
|
|
|
self.assertFalse(self.request.session['is_root'])
|