test_mixins.py 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. from unittest import mock
  2. from django.contrib.auth import models
  3. from django.contrib.auth.mixins import (
  4. LoginRequiredMixin, PermissionRequiredMixin, UserPassesTestMixin,
  5. )
  6. from django.contrib.auth.models import AnonymousUser
  7. from django.core.exceptions import PermissionDenied
  8. from django.http import HttpResponse
  9. from django.test import RequestFactory, TestCase
  10. from django.views.generic import View
  11. class AlwaysTrueMixin(UserPassesTestMixin):
  12. def test_func(self):
  13. return True
  14. class AlwaysFalseMixin(UserPassesTestMixin):
  15. def test_func(self):
  16. return False
  17. class EmptyResponseView(View):
  18. def get(self, request, *args, **kwargs):
  19. return HttpResponse()
  20. class AlwaysTrueView(AlwaysTrueMixin, EmptyResponseView):
  21. pass
  22. class AlwaysFalseView(AlwaysFalseMixin, EmptyResponseView):
  23. pass
  24. class StackedMixinsView1(LoginRequiredMixin, PermissionRequiredMixin, EmptyResponseView):
  25. permission_required = ['auth_tests.add_customuser', 'auth_tests.change_customuser']
  26. raise_exception = True
  27. class StackedMixinsView2(PermissionRequiredMixin, LoginRequiredMixin, EmptyResponseView):
  28. permission_required = ['auth_tests.add_customuser', 'auth_tests.change_customuser']
  29. raise_exception = True
  30. class AccessMixinTests(TestCase):
  31. factory = RequestFactory()
  32. def test_stacked_mixins_success(self):
  33. user = models.User.objects.create(username='joe', password='qwerty')
  34. perms = models.Permission.objects.filter(codename__in=('add_customuser', 'change_customuser'))
  35. user.user_permissions.add(*perms)
  36. request = self.factory.get('/rand')
  37. request.user = user
  38. view = StackedMixinsView1.as_view()
  39. response = view(request)
  40. self.assertEqual(response.status_code, 200)
  41. view = StackedMixinsView2.as_view()
  42. response = view(request)
  43. self.assertEqual(response.status_code, 200)
  44. def test_stacked_mixins_missing_permission(self):
  45. user = models.User.objects.create(username='joe', password='qwerty')
  46. perms = models.Permission.objects.filter(codename__in=('add_customuser',))
  47. user.user_permissions.add(*perms)
  48. request = self.factory.get('/rand')
  49. request.user = user
  50. view = StackedMixinsView1.as_view()
  51. with self.assertRaises(PermissionDenied):
  52. view(request)
  53. view = StackedMixinsView2.as_view()
  54. with self.assertRaises(PermissionDenied):
  55. view(request)
  56. def test_access_mixin_permission_denied_response(self):
  57. user = models.User.objects.create(username='joe', password='qwerty')
  58. # Authenticated users receive PermissionDenied.
  59. request = self.factory.get('/rand')
  60. request.user = user
  61. view = AlwaysFalseView.as_view()
  62. with self.assertRaises(PermissionDenied):
  63. view(request)
  64. # Anonymous users are redirected to the login page.
  65. request.user = AnonymousUser()
  66. response = view(request)
  67. self.assertEqual(response.status_code, 302)
  68. self.assertEqual(response.url, '/accounts/login/?next=/rand')
  69. @mock.patch.object(models.User, 'is_authenticated', False)
  70. def test_stacked_mixins_not_logged_in(self):
  71. user = models.User.objects.create(username='joe', password='qwerty')
  72. perms = models.Permission.objects.filter(codename__in=('add_customuser', 'change_customuser'))
  73. user.user_permissions.add(*perms)
  74. request = self.factory.get('/rand')
  75. request.user = user
  76. view = StackedMixinsView1.as_view()
  77. with self.assertRaises(PermissionDenied):
  78. view(request)
  79. view = StackedMixinsView2.as_view()
  80. with self.assertRaises(PermissionDenied):
  81. view(request)
  82. class UserPassesTestTests(TestCase):
  83. factory = RequestFactory()
  84. def _test_redirect(self, view=None, url='/accounts/login/?next=/rand'):
  85. if not view:
  86. view = AlwaysFalseView.as_view()
  87. request = self.factory.get('/rand')
  88. request.user = AnonymousUser()
  89. response = view(request)
  90. self.assertEqual(response.status_code, 302)
  91. self.assertEqual(response.url, url)
  92. def test_default(self):
  93. self._test_redirect()
  94. def test_custom_redirect_url(self):
  95. class AView(AlwaysFalseView):
  96. login_url = '/login/'
  97. self._test_redirect(AView.as_view(), '/login/?next=/rand')
  98. def test_custom_redirect_parameter(self):
  99. class AView(AlwaysFalseView):
  100. redirect_field_name = 'goto'
  101. self._test_redirect(AView.as_view(), '/accounts/login/?goto=/rand')
  102. def test_no_redirect_parameter(self):
  103. class AView(AlwaysFalseView):
  104. redirect_field_name = None
  105. self._test_redirect(AView.as_view(), '/accounts/login/')
  106. def test_raise_exception(self):
  107. class AView(AlwaysFalseView):
  108. raise_exception = True
  109. request = self.factory.get('/rand')
  110. request.user = AnonymousUser()
  111. with self.assertRaises(PermissionDenied):
  112. AView.as_view()(request)
  113. def test_raise_exception_custom_message(self):
  114. msg = "You don't have access here"
  115. class AView(AlwaysFalseView):
  116. raise_exception = True
  117. permission_denied_message = msg
  118. request = self.factory.get('/rand')
  119. request.user = AnonymousUser()
  120. view = AView.as_view()
  121. with self.assertRaises(PermissionDenied) as cm:
  122. view(request)
  123. self.assertEqual(cm.exception.args[0], msg)
  124. def test_raise_exception_custom_message_function(self):
  125. msg = "You don't have access here"
  126. class AView(AlwaysFalseView):
  127. raise_exception = True
  128. def get_permission_denied_message(self):
  129. return msg
  130. request = self.factory.get('/rand')
  131. request.user = AnonymousUser()
  132. view = AView.as_view()
  133. with self.assertRaises(PermissionDenied) as cm:
  134. view(request)
  135. self.assertEqual(cm.exception.args[0], msg)
  136. def test_user_passes(self):
  137. view = AlwaysTrueView.as_view()
  138. request = self.factory.get('/rand')
  139. request.user = AnonymousUser()
  140. response = view(request)
  141. self.assertEqual(response.status_code, 200)
  142. class LoginRequiredMixinTests(TestCase):
  143. factory = RequestFactory()
  144. @classmethod
  145. def setUpTestData(cls):
  146. cls.user = models.User.objects.create(username='joe', password='qwerty')
  147. def test_login_required(self):
  148. """
  149. login_required works on a simple view wrapped in a login_required
  150. decorator.
  151. """
  152. class AView(LoginRequiredMixin, EmptyResponseView):
  153. pass
  154. view = AView.as_view()
  155. request = self.factory.get('/rand')
  156. request.user = AnonymousUser()
  157. response = view(request)
  158. self.assertEqual(response.status_code, 302)
  159. self.assertEqual('/accounts/login/?next=/rand', response.url)
  160. request = self.factory.get('/rand')
  161. request.user = self.user
  162. response = view(request)
  163. self.assertEqual(response.status_code, 200)
  164. class PermissionsRequiredMixinTests(TestCase):
  165. factory = RequestFactory()
  166. @classmethod
  167. def setUpTestData(cls):
  168. cls.user = models.User.objects.create(username='joe', password='qwerty')
  169. perms = models.Permission.objects.filter(codename__in=('add_customuser', 'change_customuser'))
  170. cls.user.user_permissions.add(*perms)
  171. def test_many_permissions_pass(self):
  172. class AView(PermissionRequiredMixin, EmptyResponseView):
  173. permission_required = ['auth_tests.add_customuser', 'auth_tests.change_customuser']
  174. request = self.factory.get('/rand')
  175. request.user = self.user
  176. resp = AView.as_view()(request)
  177. self.assertEqual(resp.status_code, 200)
  178. def test_single_permission_pass(self):
  179. class AView(PermissionRequiredMixin, EmptyResponseView):
  180. permission_required = 'auth_tests.add_customuser'
  181. request = self.factory.get('/rand')
  182. request.user = self.user
  183. resp = AView.as_view()(request)
  184. self.assertEqual(resp.status_code, 200)
  185. def test_permissioned_denied_redirect(self):
  186. class AView(PermissionRequiredMixin, EmptyResponseView):
  187. permission_required = [
  188. 'auth_tests.add_customuser', 'auth_tests.change_customuser', 'nonexistent-permission',
  189. ]
  190. # Authenticated users receive PermissionDenied.
  191. request = self.factory.get('/rand')
  192. request.user = self.user
  193. with self.assertRaises(PermissionDenied):
  194. AView.as_view()(request)
  195. # Anonymous users are redirected to the login page.
  196. request.user = AnonymousUser()
  197. resp = AView.as_view()(request)
  198. self.assertEqual(resp.status_code, 302)
  199. def test_permissioned_denied_exception_raised(self):
  200. class AView(PermissionRequiredMixin, EmptyResponseView):
  201. permission_required = [
  202. 'auth_tests.add_customuser', 'auth_tests.change_customuser', 'nonexistent-permission',
  203. ]
  204. raise_exception = True
  205. request = self.factory.get('/rand')
  206. request.user = self.user
  207. with self.assertRaises(PermissionDenied):
  208. AView.as_view()(request)