Newer
Older
pydwiki / jwt_auth / tests / tests_views.py
  1. from typing import cast
  2.  
  3. import pyotp
  4. from django.http import HttpResponse
  5. from django.urls import reverse
  6. from rest_framework import status
  7. from rest_framework.response import Response
  8. from rest_framework.test import APIClient, APITestCase
  9.  
  10. from accounts.models import CustomUser, EmailAddress
  11.  
  12.  
  13. class MfaAuthViewSetTestCase(APITestCase):
  14.  
  15. def setUp(self):
  16. """テスト用のユーザー、メールアドレスを設定します。
  17. 次のユーザー、とユーザーに紐づくメールアドレスを設定します。
  18.  
  19. User:
  20. login_id: testuser
  21. username: Test User
  22. is_staff: True
  23. is_active: True
  24. is_superuser: False
  25. is_mfa_enabled: False
  26. password_changed: False
  27. mail: [
  28. test1@example.com, is_primary: True
  29. test2@example.com, is_primary: False
  30. ]
  31. """
  32. self.user = CustomUser.objects.create(
  33. login_id="testuser",
  34. username="Test User",
  35. is_staff=True,
  36. is_active=True,
  37. is_superuser=False,
  38. is_mfa_enabled=False,
  39. password_changed=False,
  40. )
  41. self.user.set_password("password")
  42. self.user.save()
  43. self.email1 = EmailAddress.objects.create(
  44. user=self.user,
  45. email="test1@example.com",
  46. is_primary=True,
  47. )
  48. self.email2 = EmailAddress.objects.create(
  49. user=self.user,
  50. email="test2@example.com",
  51. is_primary=False,
  52. )
  53. # アクセストークンを取得する。
  54. token_uri = reverse("token_obtain_pair")
  55. response = self.client.post(
  56. token_uri,
  57. {"login_id": "testuser", "password": "password"},
  58. format="json",
  59. )
  60. response = cast(HttpResponse, response)
  61. self.assertEqual(response.status_code, status.HTTP_200_OK)
  62.  
  63. response = cast(Response, response)
  64. if response.data:
  65. self.accessToken = response.data["access"]
  66. self.client: APIClient = cast(APIClient, self.client)
  67. self.client.credentials(HTTP_AUTHORIZATION="Bearer " + self.accessToken)
  68. else:
  69. raise Exception("Failed to get access token")
  70.  
  71. # MFA を有効にする
  72. self.user.is_mfa_enabled = True
  73. self.user.save()
  74.  
  75. def test_mfa_setup(self):
  76. """ユーザーの MFA を取得する。"""
  77.  
  78. # MFA 取得
  79. setup_uri = reverse("mfa-setup")
  80. response = self.client.get(setup_uri)
  81. response = cast(HttpResponse, response)
  82. self.assertEqual(response.status_code, status.HTTP_200_OK)
  83.  
  84. response = cast(Response, response)
  85. if not response.data:
  86. self.fail("MFA setup failed")
  87.  
  88. otp_url = response.data["otp_url"]
  89. qr_code = response.data["qr_code"]
  90. self.assertTrue(otp_url.startswith(f"otpauth://totp/{self.user.login_id}?secret="))
  91. self.assertIsNotNone(qr_code)
  92.  
  93. def test_mfa_verify_success(self):
  94. """MFA の検証が成功することをテスト"""
  95.  
  96. # MFA 取得 & 生成
  97. setup_uri = reverse("mfa-setup")
  98. response = self.client.get(setup_uri)
  99. response = cast(HttpResponse, response)
  100. self.assertEqual(response.status_code, status.HTTP_200_OK)
  101.  
  102. response = cast(Response, response)
  103. if not response.data:
  104. self.fail("MFA setup failed")
  105.  
  106. otp_url = response.data["otp_url"]
  107. qr_code = response.data["qr_code"]
  108. self.assertTrue(otp_url.startswith(f"otpauth://totp/{self.user.login_id}?secret="))
  109. self.assertIsNotNone(qr_code)
  110.  
  111. # 生成した TOTP URI から TOTP の値を取得する。
  112. totp = pyotp.parse_uri(otp_url)
  113. if type(totp) is not pyotp.TOTP:
  114. self.fail("Invalid TOTP URI")
  115. otp = totp.now()
  116.  
  117. # MFA を検証
  118. verify_uri = reverse("mfa-verify")
  119. response = self.client.post(verify_uri, {"otp": otp})
  120.  
  121. response = cast(HttpResponse, response)
  122. self.assertEqual(response.status_code, status.HTTP_200_OK)
  123.  
  124. response = cast(Response, response)
  125. if not response.data:
  126. self.fail("MFA failed")
  127. self.assertEqual(response.data["message"], "MFA enabled successfully")
  128.  
  129. def test_mfa_verify_failure(self):
  130. """MFA の検証が失敗することをテスト"""
  131.  
  132. # MFA 取得 & 生成
  133. otp = "123456"
  134.  
  135. # MFA を検証
  136. verify_uri = reverse("mfa-verify")
  137. response = self.client.post(verify_uri, {"otp": otp})
  138.  
  139. response = cast(HttpResponse, response)
  140. print(f"{response}")
  141. self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)