Skip to content

Commit

Permalink
fix(usersessions): Handle LOGOUT_ON_PASSWORD_CHANGE
Browse files Browse the repository at this point in the history
  • Loading branch information
pennersr committed Jan 15, 2024
1 parent 3b65b11 commit befdf9b
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 5 deletions.
10 changes: 10 additions & 0 deletions ChangeLog.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
0.60.1 (unreleased)
*******************

Fixes
-----

- User sessions: after changing your password in case of ``ACCOUNT_LOGOUT_ON_PASSWORD_CHANGE = False``, the list of
sessions woud be empty instead of showing your current session.


0.60.0 (2024-01-05)
*******************

Expand Down
8 changes: 7 additions & 1 deletion allauth/usersessions/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,13 @@ class UserSessionsConfig(AppConfig):
)

def ready(self):
from allauth.account.signals import user_logged_in
from allauth.account.signals import (
password_changed,
password_set,
user_logged_in,
)
from allauth.usersessions import signals

user_logged_in.connect(receiver=signals.on_user_logged_in)
for sig in [password_set, password_changed]:
sig.connect(receiver=signals.on_password_changed)
21 changes: 17 additions & 4 deletions allauth/usersessions/models.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
from importlib import import_module

from django.conf import settings
from django.contrib.auth import get_user
from django.db import models
from django.http import HttpRequest
from django.utils import timezone
from django.utils.translation import gettext_lazy as _

Expand Down Expand Up @@ -51,13 +53,24 @@ class UserSession(models.Model):
def __str__(self):
return f"{self.ip} ({self.user_agent})"

def exists(self):
def _session_store(self, *args):
engine = import_module(settings.SESSION_ENGINE)
store = engine.SessionStore()
return store.exists(self.session_key)
return engine.SessionStore(*args)

def exists(self):
return self._session_store().exists(self.session_key)

def purge(self):
if not self.exists():
purge = not self.exists()
if not purge:
# Even if the session still exists, it might be the case that the
# user session hash is out of sync. So, let's see if
# `django.contrib.auth` can find a user...
request = HttpRequest()
request.session = self._session_store(self.session_key)
user = get_user(request)
purge = not user or user.is_anonymous
if purge:
self.delete()
return True
return False
Expand Down
8 changes: 8 additions & 0 deletions allauth/usersessions/signals.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
from allauth.account import app_settings

from .models import UserSession


def on_user_logged_in(sender, **kwargs):
request = kwargs["request"]
UserSession.objects.create_from_request(request)


def on_password_changed(sender, **kwargs):
if not app_settings.LOGOUT_ON_PASSWORD_CHANGE:
request = kwargs["request"]
UserSession.objects.create_from_request(request)
28 changes: 28 additions & 0 deletions allauth/usersessions/tests/test_views.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from django.test import Client
from django.urls import reverse

import pytest

from allauth.usersessions.models import UserSession


Expand Down Expand Up @@ -30,3 +32,29 @@ def test_overall_flow(user, user_password):
assert resp["location"] == reverse("account_login") + "?next=" + reverse(
"usersessions_list"
)


@pytest.mark.parametrize("logout_on_passwd_change", [True, False])
def test_change_password_updates_user_session(
settings, logout_on_passwd_change, client, user, user_password, password_factory
):
settings.ACCOUNT_LOGOUT_ON_PASSWORD_CHANGE = logout_on_passwd_change
resp = client.post(
reverse("account_login"),
{"login": user.username, "password": user_password},
)
assert resp.status_code == 302
assert len(UserSession.objects.purge_and_list(user)) == 1

new_password = password_factory()
resp = client.post(
reverse("account_change_password"),
{
"oldpassword": user_password,
"password1": new_password,
"password2": new_password,
},
)
assert len(UserSession.objects.purge_and_list(user)) == (
0 if logout_on_passwd_change else 1
)

0 comments on commit befdf9b

Please sign in to comment.