1. from unittest import mock
    
  2. 
    
  3. from django.contrib.auth import models
    
  4. from django.contrib.auth.mixins import (
    
  5.     LoginRequiredMixin,
    
  6.     PermissionRequiredMixin,
    
  7.     UserPassesTestMixin,
    
  8. )
    
  9. from django.contrib.auth.models import AnonymousUser
    
  10. from django.core.exceptions import PermissionDenied
    
  11. from django.http import HttpResponse
    
  12. from django.test import RequestFactory, SimpleTestCase, TestCase
    
  13. from django.views.generic import View
    
  14. 
    
  15. 
    
  16. class AlwaysTrueMixin(UserPassesTestMixin):
    
  17.     def test_func(self):
    
  18.         return True
    
  19. 
    
  20. 
    
  21. class AlwaysFalseMixin(UserPassesTestMixin):
    
  22.     def test_func(self):
    
  23.         return False
    
  24. 
    
  25. 
    
  26. class EmptyResponseView(View):
    
  27.     def get(self, request, *args, **kwargs):
    
  28.         return HttpResponse()
    
  29. 
    
  30. 
    
  31. class AlwaysTrueView(AlwaysTrueMixin, EmptyResponseView):
    
  32.     pass
    
  33. 
    
  34. 
    
  35. class AlwaysFalseView(AlwaysFalseMixin, EmptyResponseView):
    
  36.     pass
    
  37. 
    
  38. 
    
  39. class StackedMixinsView1(
    
  40.     LoginRequiredMixin, PermissionRequiredMixin, EmptyResponseView
    
  41. ):
    
  42.     permission_required = ["auth_tests.add_customuser", "auth_tests.change_customuser"]
    
  43.     raise_exception = True
    
  44. 
    
  45. 
    
  46. class StackedMixinsView2(
    
  47.     PermissionRequiredMixin, LoginRequiredMixin, EmptyResponseView
    
  48. ):
    
  49.     permission_required = ["auth_tests.add_customuser", "auth_tests.change_customuser"]
    
  50.     raise_exception = True
    
  51. 
    
  52. 
    
  53. class AccessMixinTests(TestCase):
    
  54.     factory = RequestFactory()
    
  55. 
    
  56.     def test_stacked_mixins_success(self):
    
  57.         user = models.User.objects.create(username="joe", password="qwerty")
    
  58.         perms = models.Permission.objects.filter(
    
  59.             codename__in=("add_customuser", "change_customuser")
    
  60.         )
    
  61.         user.user_permissions.add(*perms)
    
  62.         request = self.factory.get("/rand")
    
  63.         request.user = user
    
  64. 
    
  65.         view = StackedMixinsView1.as_view()
    
  66.         response = view(request)
    
  67.         self.assertEqual(response.status_code, 200)
    
  68. 
    
  69.         view = StackedMixinsView2.as_view()
    
  70.         response = view(request)
    
  71.         self.assertEqual(response.status_code, 200)
    
  72. 
    
  73.     def test_stacked_mixins_missing_permission(self):
    
  74.         user = models.User.objects.create(username="joe", password="qwerty")
    
  75.         perms = models.Permission.objects.filter(codename__in=("add_customuser",))
    
  76.         user.user_permissions.add(*perms)
    
  77.         request = self.factory.get("/rand")
    
  78.         request.user = user
    
  79. 
    
  80.         view = StackedMixinsView1.as_view()
    
  81.         with self.assertRaises(PermissionDenied):
    
  82.             view(request)
    
  83. 
    
  84.         view = StackedMixinsView2.as_view()
    
  85.         with self.assertRaises(PermissionDenied):
    
  86.             view(request)
    
  87. 
    
  88.     def test_access_mixin_permission_denied_response(self):
    
  89.         user = models.User.objects.create(username="joe", password="qwerty")
    
  90.         # Authenticated users receive PermissionDenied.
    
  91.         request = self.factory.get("/rand")
    
  92.         request.user = user
    
  93.         view = AlwaysFalseView.as_view()
    
  94.         with self.assertRaises(PermissionDenied):
    
  95.             view(request)
    
  96.         # Anonymous users are redirected to the login page.
    
  97.         request.user = AnonymousUser()
    
  98.         response = view(request)
    
  99.         self.assertEqual(response.status_code, 302)
    
  100.         self.assertEqual(response.url, "/accounts/login/?next=/rand")
    
  101. 
    
  102.     def test_access_mixin_permission_denied_remote_login_url(self):
    
  103.         class AView(AlwaysFalseView):
    
  104.             login_url = "https://www.remote.example.com/login"
    
  105. 
    
  106.         view = AView.as_view()
    
  107.         request = self.factory.get("/rand")
    
  108.         request.user = AnonymousUser()
    
  109.         response = view(request)
    
  110.         self.assertEqual(response.status_code, 302)
    
  111.         self.assertEqual(
    
  112.             response.url,
    
  113.             "https://www.remote.example.com/login?next=http%3A//testserver/rand",
    
  114.         )
    
  115. 
    
  116.     @mock.patch.object(models.User, "is_authenticated", False)
    
  117.     def test_stacked_mixins_not_logged_in(self):
    
  118.         user = models.User.objects.create(username="joe", password="qwerty")
    
  119.         perms = models.Permission.objects.filter(
    
  120.             codename__in=("add_customuser", "change_customuser")
    
  121.         )
    
  122.         user.user_permissions.add(*perms)
    
  123.         request = self.factory.get("/rand")
    
  124.         request.user = user
    
  125. 
    
  126.         view = StackedMixinsView1.as_view()
    
  127.         with self.assertRaises(PermissionDenied):
    
  128.             view(request)
    
  129. 
    
  130.         view = StackedMixinsView2.as_view()
    
  131.         with self.assertRaises(PermissionDenied):
    
  132.             view(request)
    
  133. 
    
  134. 
    
  135. class UserPassesTestTests(SimpleTestCase):
    
  136.     factory = RequestFactory()
    
  137. 
    
  138.     def _test_redirect(self, view=None, url="/accounts/login/?next=/rand"):
    
  139.         if not view:
    
  140.             view = AlwaysFalseView.as_view()
    
  141.         request = self.factory.get("/rand")
    
  142.         request.user = AnonymousUser()
    
  143.         response = view(request)
    
  144.         self.assertEqual(response.status_code, 302)
    
  145.         self.assertEqual(response.url, url)
    
  146. 
    
  147.     def test_default(self):
    
  148.         self._test_redirect()
    
  149. 
    
  150.     def test_custom_redirect_url(self):
    
  151.         class AView(AlwaysFalseView):
    
  152.             login_url = "/login/"
    
  153. 
    
  154.         self._test_redirect(AView.as_view(), "/login/?next=/rand")
    
  155. 
    
  156.     def test_custom_redirect_parameter(self):
    
  157.         class AView(AlwaysFalseView):
    
  158.             redirect_field_name = "goto"
    
  159. 
    
  160.         self._test_redirect(AView.as_view(), "/accounts/login/?goto=/rand")
    
  161. 
    
  162.     def test_no_redirect_parameter(self):
    
  163.         class AView(AlwaysFalseView):
    
  164.             redirect_field_name = None
    
  165. 
    
  166.         self._test_redirect(AView.as_view(), "/accounts/login/")
    
  167. 
    
  168.     def test_raise_exception(self):
    
  169.         class AView(AlwaysFalseView):
    
  170.             raise_exception = True
    
  171. 
    
  172.         request = self.factory.get("/rand")
    
  173.         request.user = AnonymousUser()
    
  174.         with self.assertRaises(PermissionDenied):
    
  175.             AView.as_view()(request)
    
  176. 
    
  177.     def test_raise_exception_custom_message(self):
    
  178.         msg = "You don't have access here"
    
  179. 
    
  180.         class AView(AlwaysFalseView):
    
  181.             raise_exception = True
    
  182.             permission_denied_message = msg
    
  183. 
    
  184.         request = self.factory.get("/rand")
    
  185.         request.user = AnonymousUser()
    
  186.         view = AView.as_view()
    
  187.         with self.assertRaisesMessage(PermissionDenied, msg):
    
  188.             view(request)
    
  189. 
    
  190.     def test_raise_exception_custom_message_function(self):
    
  191.         msg = "You don't have access here"
    
  192. 
    
  193.         class AView(AlwaysFalseView):
    
  194.             raise_exception = True
    
  195. 
    
  196.             def get_permission_denied_message(self):
    
  197.                 return msg
    
  198. 
    
  199.         request = self.factory.get("/rand")
    
  200.         request.user = AnonymousUser()
    
  201.         view = AView.as_view()
    
  202.         with self.assertRaisesMessage(PermissionDenied, msg):
    
  203.             view(request)
    
  204. 
    
  205.     def test_user_passes(self):
    
  206.         view = AlwaysTrueView.as_view()
    
  207.         request = self.factory.get("/rand")
    
  208.         request.user = AnonymousUser()
    
  209.         response = view(request)
    
  210.         self.assertEqual(response.status_code, 200)
    
  211. 
    
  212. 
    
  213. class LoginRequiredMixinTests(TestCase):
    
  214.     factory = RequestFactory()
    
  215. 
    
  216.     @classmethod
    
  217.     def setUpTestData(cls):
    
  218.         cls.user = models.User.objects.create(username="joe", password="qwerty")
    
  219. 
    
  220.     def test_login_required(self):
    
  221.         """
    
  222.         login_required works on a simple view wrapped in a login_required
    
  223.         decorator.
    
  224.         """
    
  225. 
    
  226.         class AView(LoginRequiredMixin, EmptyResponseView):
    
  227.             pass
    
  228. 
    
  229.         view = AView.as_view()
    
  230. 
    
  231.         request = self.factory.get("/rand")
    
  232.         request.user = AnonymousUser()
    
  233.         response = view(request)
    
  234.         self.assertEqual(response.status_code, 302)
    
  235.         self.assertEqual("/accounts/login/?next=/rand", response.url)
    
  236.         request = self.factory.get("/rand")
    
  237.         request.user = self.user
    
  238.         response = view(request)
    
  239.         self.assertEqual(response.status_code, 200)
    
  240. 
    
  241. 
    
  242. class PermissionsRequiredMixinTests(TestCase):
    
  243.     factory = RequestFactory()
    
  244. 
    
  245.     @classmethod
    
  246.     def setUpTestData(cls):
    
  247.         cls.user = models.User.objects.create(username="joe", password="qwerty")
    
  248.         perms = models.Permission.objects.filter(
    
  249.             codename__in=("add_customuser", "change_customuser")
    
  250.         )
    
  251.         cls.user.user_permissions.add(*perms)
    
  252. 
    
  253.     def test_many_permissions_pass(self):
    
  254.         class AView(PermissionRequiredMixin, EmptyResponseView):
    
  255.             permission_required = [
    
  256.                 "auth_tests.add_customuser",
    
  257.                 "auth_tests.change_customuser",
    
  258.             ]
    
  259. 
    
  260.         request = self.factory.get("/rand")
    
  261.         request.user = self.user
    
  262.         resp = AView.as_view()(request)
    
  263.         self.assertEqual(resp.status_code, 200)
    
  264. 
    
  265.     def test_single_permission_pass(self):
    
  266.         class AView(PermissionRequiredMixin, EmptyResponseView):
    
  267.             permission_required = "auth_tests.add_customuser"
    
  268. 
    
  269.         request = self.factory.get("/rand")
    
  270.         request.user = self.user
    
  271.         resp = AView.as_view()(request)
    
  272.         self.assertEqual(resp.status_code, 200)
    
  273. 
    
  274.     def test_permissioned_denied_redirect(self):
    
  275.         class AView(PermissionRequiredMixin, EmptyResponseView):
    
  276.             permission_required = [
    
  277.                 "auth_tests.add_customuser",
    
  278.                 "auth_tests.change_customuser",
    
  279.                 "nonexistent-permission",
    
  280.             ]
    
  281. 
    
  282.         # Authenticated users receive PermissionDenied.
    
  283.         request = self.factory.get("/rand")
    
  284.         request.user = self.user
    
  285.         with self.assertRaises(PermissionDenied):
    
  286.             AView.as_view()(request)
    
  287.         # Anonymous users are redirected to the login page.
    
  288.         request.user = AnonymousUser()
    
  289.         resp = AView.as_view()(request)
    
  290.         self.assertEqual(resp.status_code, 302)
    
  291. 
    
  292.     def test_permissioned_denied_exception_raised(self):
    
  293.         class AView(PermissionRequiredMixin, EmptyResponseView):
    
  294.             permission_required = [
    
  295.                 "auth_tests.add_customuser",
    
  296.                 "auth_tests.change_customuser",
    
  297.                 "nonexistent-permission",
    
  298.             ]
    
  299.             raise_exception = True
    
  300. 
    
  301.         request = self.factory.get("/rand")
    
  302.         request.user = self.user
    
  303.         with self.assertRaises(PermissionDenied):
    
  304.             AView.as_view()(request)