From 217b0b47da02f7af03482cf27daeddf88ba7df80 Mon Sep 17 00:00:00 2001 From: SKairinos Date: Wed, 27 Sep 2023 18:00:19 +0100 Subject: [PATCH] fix session creation logic --- codeforlife/user/migrations/0001_initial.py | 2 +- codeforlife/user/models/session.py | 66 ++++++++++----------- manage.py | 2 +- 3 files changed, 34 insertions(+), 36 deletions(-) diff --git a/codeforlife/user/migrations/0001_initial.py b/codeforlife/user/migrations/0001_initial.py index f0a115a1..ea3cab55 100644 --- a/codeforlife/user/migrations/0001_initial.py +++ b/codeforlife/user/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 3.2.20 on 2023-09-27 14:30 +# Generated by Django 3.2.20 on 2023-09-27 15:03 import django.contrib.auth.models from django.db import migrations, models diff --git a/codeforlife/user/models/session.py b/codeforlife/user/models/session.py index 72bb8bdb..f501ed11 100644 --- a/codeforlife/user/models/session.py +++ b/codeforlife/user/models/session.py @@ -45,6 +45,10 @@ class Session(AbstractBaseSession): on_delete=models.CASCADE, ) + @property + def is_expired(self): + return self.expire_date < timezone.now() + @property def store(self): return self.get_session_store_class()(self.session_key) @@ -58,7 +62,8 @@ class SessionStore(DBStore): """ A custom session store interface to support: 1. creating only one session per user; - 2. clearing expired sessions per user. + 2. setting a session's auth factors; + 3. clearing a user's expired sessions. https://docs.djangoproject.com/en/3.2/topics/http/sessions/#example """ @@ -68,45 +73,38 @@ def get_model_class(cls): def create_model_instance(self, data): Session = self.get_model_class() - session: Session = None + session: Session - # Get user ID if not an anon user. try: user_id = int(data.get(SESSION_KEY)) - except (ValueError, TypeError): - user_id = None - - if user_id: - # Clear expired sessions for user. - self.clear_expired(user_id) try: - # Return user's non-expired session and update its data. - session: Session = Session.objects.get(user_id=user_id) - session.session_data = self.encode(data) - return session + session = Session.objects.get(user_id=user_id) + + if session.is_expired: + self.clear_expired(user_id) + session = super().create_model_instance(data) + # Despite having the user's ID, DO NOT set session.user. + else: + session.session_data = self.encode(data) + except Session.DoesNotExist: - # Get and set user's enabled auth factors in the session. - user = User.objects.get(id=user_id) - else: - user = None - - # Create session. - session = super().create_model_instance(data) - session.user = user - session.save() - - # Create session auth factors. - if user: - session_auth_factor.SessionAuthFactor.objects.bulk_create( - [ - session_auth_factor.SessionAuthFactor( - session=session, - auth_factor=auth_factor, - ) - for auth_factor in user.auth_factors - ] - ) + session = Session.objects.get(session_key=self.session_key) + session.user = user.User.objects.get(id=user_id) + session.session_data = self.encode(data) + session_auth_factor.SessionAuthFactor.objects.bulk_create( + [ + session_auth_factor.SessionAuthFactor( + session=session, + auth_factor=auth_factor, + ) + for auth_factor in session.user.auth_factors.all() + ] + ) + + except (ValueError, TypeError): + # Create an anon session. + session = super().create_model_instance(data) return session diff --git a/manage.py b/manage.py index 4397d501..020259c4 100644 --- a/manage.py +++ b/manage.py @@ -10,7 +10,7 @@ "django.contrib.messages", "django.contrib.staticfiles", "django.contrib.sites", - "codeforlife.user.apps.UserConfig", + "codeforlife.user", "aimmo", # TODO: remove this "game", # TODO: remove this "common", # TODO: remove this