Skip to content

Commit

Permalink
fixup! [#2816] Split user/password auth from token verification
Browse files Browse the repository at this point in the history
  • Loading branch information
swrichards committed Oct 17, 2024
1 parent e1899ae commit afc0998
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 34 deletions.
67 changes: 35 additions & 32 deletions src/open_inwoner/accounts/backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,29 +27,31 @@ class UserModelEmailBackend(ModelBackend):
"""

def authenticate(self, request, username=None, password=None):
if not username or not password:
return

User = get_user_model()
if username and password:
try:
user = User.objects.get(
email__iexact=username,
login_type=LoginTypeChoices.default,
)
if check_password(
password, user.password
) and self.user_can_authenticate(user):
return user
except User.MultipleObjectsReturned:
# Found multiple users with this email (shouldn't happen if we added checks)
# Run the default password hasher once to reduce the timing
# difference between an existing and a nonexistent user (#20760).
User().set_password(password)
return None
except User.DoesNotExist:
# No user was found, return None - triggers default login failed
# Run the default password hasher once to reduce the timing
# difference between an existing and a nonexistent user (#20760).
User().set_password(password)
return None
try:
user = User.objects.get(
email__iexact=username,
login_type=LoginTypeChoices.default,
)
if check_password(password, user.password) and self.user_can_authenticate(
user
):
return user
except User.MultipleObjectsReturned:
# Found multiple users with this email (shouldn't happen if we added checks)
# Run the default password hasher once to reduce the timing
# difference between an existing and a nonexistent user (#20760).
User().set_password(password)
return None
except User.DoesNotExist:
# No user was found, return None - triggers default login failed
# Run the default password hasher once to reduce the timing
# difference between an existing and a nonexistent user (#20760).
User().set_password(password)
return None


class Verify2FATokenBackend(BaseBackend):
Expand All @@ -58,17 +60,18 @@ class Verify2FATokenBackend(BaseBackend):
"""

def authenticate(self, request, *, user=None, token=None):
# 2FA with sms verification
if user and token:
accepted, drift = accept_totp(
key=user.seed,
response=token,
period=getattr(settings, "ACCOUNTS_USER_TOKEN_EXPIRE_TIME", 300),
)
if not accepted:
return None
if not user or not token:
return

return user
accepted, drift = accept_totp(
key=user.seed,
response=token,
period=getattr(settings, "ACCOUNTS_USER_TOKEN_EXPIRE_TIME", 300),
)
if not accepted:
return None

return user


class CustomAxesBackend(AxesBackend):
Expand Down
4 changes: 2 additions & 2 deletions src/open_inwoner/accounts/tests/test_backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ class UserModelEmailBackendTestCase(TestCase):
def setUpTestData(cls):
super().setUpTestData()

cls.password = "keepitsecert"
cls.password = "keepitsecret"
cls.user = UserFactory(
login_type=LoginTypeChoices.default, password=cls.password
)
Expand Down Expand Up @@ -142,6 +142,7 @@ def test_missing_username_and_or_password_returns_none(self):
"open_inwoner.accounts.backends.Verify2FATokenBackend",
]
)
@freeze_time("2023-05-22 12:05:01")
class Verify2FATokenBackendTestCase(TestCase):
@classmethod
def setUpTestData(cls):
Expand All @@ -151,7 +152,6 @@ def setUpTestData(cls):
cls.expires_in = getattr(settings, "ACCOUNTS_USER_TOKEN_EXPIRE_TIME", 300)
cls.make_token = lambda: totp(cls.user.seed, period=cls.expires_in)

@freeze_time("2023-05-22 12:05:01")
def test_valid_token_and_user_returns_user(self):
request = RequestFactory().get(reverse("verify_token"))

Expand Down

0 comments on commit afc0998

Please sign in to comment.