diff --git a/opentech/apply/users/tests/factories.py b/opentech/apply/users/tests/factories.py index 8db74b40f779c61361dc8f2b05e6805015b70cb5..ea11d35ec695ddcbff5333b98b14f357ad616271 100644 --- a/opentech/apply/users/tests/factories.py +++ b/opentech/apply/users/tests/factories.py @@ -1,5 +1,8 @@ +import uuid + from django.contrib.auth import get_user_model from django.contrib.auth.models import Group +from django.utils.text import slugify import factory @@ -18,7 +21,7 @@ class UserFactory(factory.DjangoModelFactory): class Meta: model = get_user_model() - email = factory.Sequence('email{}@email.com'.format) + email = factory.LazyAttribute(lambda o: '{}+{}@email.com'.format(slugify(o.full_name), uuid.uuid4())) full_name = factory.Faker('name') password = factory.PostGenerationMethodCall('set_password', 'defaultpassword') diff --git a/opentech/apply/users/tests/test_views.py b/opentech/apply/users/tests/test_views.py index 044a9566de15344b6d99487cfd18c2c462ac36d8..a62923d8a8ea701beadb2564f810b8a62c6182ac 100644 --- a/opentech/apply/users/tests/test_views.py +++ b/opentech/apply/users/tests/test_views.py @@ -3,7 +3,12 @@ from django.test import override_settings, TestCase from django.urls import reverse from opentech.apply.utils.testing.tests import BaseViewTestCase -from .factories import OAuthUserFactory, StaffFactory, UserFactory +from .factories import ( + OAuthUserFactory, + StaffFactory, + SuperUserFactory, + UserFactory, +) @override_settings(ROOT_URLCONF='opentech.apply.urls') @@ -58,3 +63,47 @@ class TestPasswordReset(BaseViewTestCase): self.assertRedirects(response, self.url(None, view_name='password_reset_done')) self.assertEqual(len(mail.outbox), 1) self.assertIn('https://testserver/account/password/reset/confirm', mail.outbox[0].body) + + +@override_settings(ROOT_URLCONF='opentech.apply.urls') +class TestBecome(TestCase): + def setUp(self): + self.staff = StaffFactory() + self.user = UserFactory() + self.superuser = SuperUserFactory() + + def become_request(self, user, target): + self.client.force_login(user) + url = reverse('users:become') + response = self.client.post(url, {'user': target.pk}, follow=True, secure=True) + return response + + def test_staff_can_become_user(self): + response = self.become_request(self.staff, self.user) + self.assertEqual(response.status_code, 200) + + def test_staff_cannot_become_superuser(self): + response = self.become_request(self.staff, self.superuser) + self.assertEqual(response.status_code, 403) + + def test_superuser_can_become_staff(self): + response = self.become_request(self.superuser, self.staff) + self.assertEqual(response.status_code, 200) + + def test_superuser_cannot_become_superuser(self): + other_superuser = SuperUserFactory() + response = self.become_request(self.superuser, other_superuser) + self.assertEqual(response.status_code, 403) + + def test_user_cannot_become_staff(self): + response = self.become_request(self.user, self.staff) + self.assertEqual(response.status_code, 403) + + def test_user_cannot_become_other_user(self): + other_user = UserFactory() + response = self.become_request(self.user, other_user) + self.assertEqual(response.status_code, 403) + + def test_user_cannot_become_superuser(self): + response = self.become_request(self.user, self.superuser) + self.assertEqual(response.status_code, 403) diff --git a/opentech/apply/users/views.py b/opentech/apply/users/views.py index 86b54c1bd48823b171b537486f88b7ebbe5a4fe9..fdc63e60a2fd6867f82035fdb638ee08833d87d9 100644 --- a/opentech/apply/users/views.py +++ b/opentech/apply/users/views.py @@ -5,6 +5,7 @@ from django.contrib.auth.decorators import login_required from django.contrib.auth.forms import AdminPasswordChangeForm from django.contrib.auth.tokens import PasswordResetTokenGenerator from django.contrib.auth.views import SuccessURLAllowedHostsMixin +from django.core.exceptions import PermissionDenied from django.http import HttpResponseRedirect from django.shortcuts import redirect, render, resolve_url from django.template.response import TemplateResponse @@ -93,8 +94,15 @@ class AccountView(UpdateView): @login_required() def become(request): - id = request.POST['user'] + if not request.user.is_apply_staff: + raise PermissionDenied() + + id = request.POST.get('user') if request.POST and id: + target_user = User.objects.get(pk=id) + if target_user.is_superuser: + raise PermissionDenied() + return login_with_id(request, id) return redirect('users:account')