diff --git a/authens/backends.py b/authens/backends.py index fcfd57a..92df47e 100644 --- a/authens/backends.py +++ b/authens/backends.py @@ -1,7 +1,7 @@ from django.contrib.auth import get_user_model from django.db import transaction -from authens.models import CASAccount +from authens.models import CASAccount, OldCASAccount from authens.utils import get_cas_client UserModel = get_user_model() @@ -101,8 +101,8 @@ class ENSCASBackend: """Handles account retrieval, creation and invalidation as described above. - If no CAS account exists, create one; - - If a CAS account exists, but with the wrong entrance year, remove it and - create a new one; + - If a CAS account exists, but with the wrong entrance year, deprecate it + into an OldCASAccount; - If a matching CAS account exists, retrieve it. """ @@ -113,6 +113,11 @@ class ENSCASBackend: try: user = UserModel.objects.get(cas_account__cas_login=cas_login) if user.cas_account.entrance_year != entrance_year: + OldCASAccount.objects.create( + user=user, + entrance_year=user.cas_account.entrance_year, + cas_login=cas_login, + ) user.cas_account.delete() user = None except UserModel.DoesNotExist: @@ -132,3 +137,27 @@ class ENSCASBackend: return UserModel.objects.get(pk=user_id) except UserModel.DoesNotExist: return None + + +class OldCASBackend: + def authenticate(self, request, cas_login=None, password=None, entrance_year=None): + if cas_login is None or password is None or entrance_year is None: + return + + try: + old_cas_acc = OldCASAccount.objects.get( + cas_login=cas_login, entrance_year=entrance_year + ) + user = old_cas_acc.user + except OldCASAccount.DoesNotExist: + # As in Django's ModelBackend, we run the password hasher once + # to avoid timing attacks + UserModel().set_password(password) + else: + if user.check_password(password) and self.user_can_authenticate(user): + return user + + def user_can_authenticate(self, user): + # Taken from Django's ModelBackend + is_active = getattr(user, "is_active", None) + return is_active or is_active is None