Skip to content
Snippets Groups Projects
Commit 3d2e02a1 authored by Todd Dembrey's avatar Todd Dembrey
Browse files

Prevent users becoming someone they shouldn't be

This was previously only enforced by gating the frontend component, this PR
tidies things up by making sure the backend prevent it happening as well
parent 767de79c
No related branches found
No related tags found
No related merge requests found
import uuid
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group from django.contrib.auth.models import Group
from django.utils.text import slugify
import factory import factory
...@@ -18,7 +21,7 @@ class UserFactory(factory.DjangoModelFactory): ...@@ -18,7 +21,7 @@ class UserFactory(factory.DjangoModelFactory):
class Meta: class Meta:
model = get_user_model() 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') full_name = factory.Faker('name')
password = factory.PostGenerationMethodCall('set_password', 'defaultpassword') password = factory.PostGenerationMethodCall('set_password', 'defaultpassword')
......
...@@ -3,7 +3,12 @@ from django.test import override_settings, TestCase ...@@ -3,7 +3,12 @@ from django.test import override_settings, TestCase
from django.urls import reverse from django.urls import reverse
from opentech.apply.utils.testing.tests import BaseViewTestCase 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') @override_settings(ROOT_URLCONF='opentech.apply.urls')
...@@ -58,3 +63,47 @@ class TestPasswordReset(BaseViewTestCase): ...@@ -58,3 +63,47 @@ class TestPasswordReset(BaseViewTestCase):
self.assertRedirects(response, self.url(None, view_name='password_reset_done')) self.assertRedirects(response, self.url(None, view_name='password_reset_done'))
self.assertEqual(len(mail.outbox), 1) self.assertEqual(len(mail.outbox), 1)
self.assertIn('https://testserver/account/password/reset/confirm', mail.outbox[0].body) 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)
...@@ -5,6 +5,7 @@ from django.contrib.auth.decorators import login_required ...@@ -5,6 +5,7 @@ from django.contrib.auth.decorators import login_required
from django.contrib.auth.forms import AdminPasswordChangeForm from django.contrib.auth.forms import AdminPasswordChangeForm
from django.contrib.auth.tokens import PasswordResetTokenGenerator from django.contrib.auth.tokens import PasswordResetTokenGenerator
from django.contrib.auth.views import SuccessURLAllowedHostsMixin from django.contrib.auth.views import SuccessURLAllowedHostsMixin
from django.core.exceptions import PermissionDenied
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect
from django.shortcuts import redirect, render, resolve_url from django.shortcuts import redirect, render, resolve_url
from django.template.response import TemplateResponse from django.template.response import TemplateResponse
...@@ -93,8 +94,15 @@ class AccountView(UpdateView): ...@@ -93,8 +94,15 @@ class AccountView(UpdateView):
@login_required() @login_required()
def become(request): 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: 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 login_with_id(request, id)
return redirect('users:account') return redirect('users:account')
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment