|
| 1 | +import datetime |
1 | 2 | from unittest.mock import patch
|
2 | 3 |
|
| 4 | +from django.conf import settings |
3 | 5 | from django.contrib import auth
|
4 | 6 | from django.test import RequestFactory, TestCase, override_settings
|
5 | 7 | from django.urls import reverse
|
6 | 8 |
|
| 9 | +from freezegun import freeze_time |
| 10 | +from oath import totp |
| 11 | + |
| 12 | +from open_inwoner.accounts.choices import LoginTypeChoices |
7 | 13 | from open_inwoner.accounts.tests.factories import UserFactory
|
8 | 14 |
|
9 | 15 |
|
@@ -69,3 +75,108 @@ def test_admin_oidc_use_correct_backend(
|
69 | 75 | result = auth.authenticate(request)
|
70 | 76 |
|
71 | 77 | self.assertEqual(result, self.user)
|
| 78 | + |
| 79 | + |
| 80 | +@override_settings( |
| 81 | + AUTHENTICATION_BACKENDS=[ |
| 82 | + "open_inwoner.accounts.backends.UserModelEmailBackend", |
| 83 | + ] |
| 84 | +) |
| 85 | +class UserModelEmailBackendTestCase(TestCase): |
| 86 | + @classmethod |
| 87 | + def setUpTestData(cls): |
| 88 | + super().setUpTestData() |
| 89 | + |
| 90 | + cls.password = "keepitsecert" |
| 91 | + cls.user = UserFactory( |
| 92 | + login_type=LoginTypeChoices.default, password=cls.password |
| 93 | + ) |
| 94 | + for login_type in LoginTypeChoices: |
| 95 | + UserFactory(login_type=login_type) |
| 96 | + |
| 97 | + def test_duplicate_emails_on_case_results_in_no_match(self): |
| 98 | + request = RequestFactory().post(reverse("login")) |
| 99 | + |
| 100 | + UserFactory(email=self.user.email.upper(), login_type=self.user.login_type) |
| 101 | + result = auth.authenticate( |
| 102 | + request, username=self.user.email, password=self.password |
| 103 | + ) |
| 104 | + self.assertEqual(result, None) |
| 105 | + |
| 106 | + def test_correct_username_password_return_user(self): |
| 107 | + request = RequestFactory().post(reverse("login")) |
| 108 | + |
| 109 | + result = auth.authenticate( |
| 110 | + request, username=self.user.email, password=self.password |
| 111 | + ) |
| 112 | + self.assertEqual(result, self.user) |
| 113 | + |
| 114 | + def test_incorrect_username_password_return_none(self): |
| 115 | + request = RequestFactory().post(reverse("login")) |
| 116 | + |
| 117 | + for username, password in ( |
| 118 | + (self.user.email, "incorrect"), |
| 119 | + ("incorrect", self.password), |
| 120 | + ): |
| 121 | + result = auth.authenticate(request, username=username, password=password) |
| 122 | + self.assertEqual(result, None) |
| 123 | + |
| 124 | + def test_missing_username_and_or_password_returns_none(self): |
| 125 | + for username in (self.user.email, "", None): |
| 126 | + for password in (self.password, "", None): |
| 127 | + if username and password: |
| 128 | + # This is the successful case, exclude it, but ensure we |
| 129 | + # also have permutations with one valid/one invalid value. |
| 130 | + continue |
| 131 | + |
| 132 | + with self.subTest(f"{username=} {password=}"): |
| 133 | + request = RequestFactory().post(reverse("login")) |
| 134 | + result = auth.authenticate( |
| 135 | + request, username=username, password=password |
| 136 | + ) |
| 137 | + self.assertEqual(result, None) |
| 138 | + |
| 139 | + |
| 140 | +@override_settings( |
| 141 | + AUTHENTICATION_BACKENDS=[ |
| 142 | + "open_inwoner.accounts.backends.Verify2FATokenBackend", |
| 143 | + ] |
| 144 | +) |
| 145 | +class Verify2FATokenBackendTestCase(TestCase): |
| 146 | + @classmethod |
| 147 | + def setUpTestData(cls): |
| 148 | + super().setUpTestData() |
| 149 | + |
| 150 | + cls.user = UserFactory(login_type=LoginTypeChoices.default) |
| 151 | + cls.expires_in = getattr(settings, "ACCOUNTS_USER_TOKEN_EXPIRE_TIME", 300) |
| 152 | + cls.make_token = lambda: totp(cls.user.seed, period=cls.expires_in) |
| 153 | + |
| 154 | + @freeze_time("2023-05-22 12:05:01") |
| 155 | + def test_valid_token_and_user_returns_user(self): |
| 156 | + request = RequestFactory().get(reverse("verify_token")) |
| 157 | + |
| 158 | + result = auth.authenticate(request, user=self.user, token=self.make_token()) |
| 159 | + self.assertEqual(result, self.user) |
| 160 | + |
| 161 | + def test_expired_token_and_valid_user_returns_none(self): |
| 162 | + request = RequestFactory().get(reverse("verify_token")) |
| 163 | + |
| 164 | + with freeze_time("2023-05-22 12:05:01") as ft: |
| 165 | + token = self.make_token() |
| 166 | + |
| 167 | + ft.tick(delta=datetime.timedelta(seconds=self.expires_in * 2)) |
| 168 | + result = auth.authenticate(request, user=self.user, token=token) |
| 169 | + self.assertEqual(result, None) |
| 170 | + |
| 171 | + def test_missing_user_and_or_token_returns_none(self): |
| 172 | + for user in (self.user.email, "", None): |
| 173 | + for token in (self.make_token(), "", None): |
| 174 | + if user and token: |
| 175 | + # This is the successful case, exclude it, but ensure we |
| 176 | + # also have permutations with one valid/one invalid value. |
| 177 | + continue |
| 178 | + |
| 179 | + with self.subTest(f"{user=} {token=}"): |
| 180 | + request = RequestFactory().get(reverse("verify_token")) |
| 181 | + result = auth.authenticate(request, user=user, token=token) |
| 182 | + self.assertEqual(result, None) |
0 commit comments