security: fix CVE-2025-29928 (#13695)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
@ -1,13 +1,14 @@
|
|||||||
"""User API Views"""
|
"""User API Views"""
|
||||||
|
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
from importlib import import_module
|
||||||
from json import loads
|
from json import loads
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
from django.contrib.auth import update_session_auth_hash
|
from django.contrib.auth import update_session_auth_hash
|
||||||
from django.contrib.auth.models import Permission
|
from django.contrib.auth.models import Permission
|
||||||
from django.contrib.sessions.backends.cache import KEY_PREFIX
|
from django.contrib.sessions.backends.base import SessionBase
|
||||||
from django.core.cache import cache
|
|
||||||
from django.db.models.functions import ExtractHour
|
from django.db.models.functions import ExtractHour
|
||||||
from django.db.transaction import atomic
|
from django.db.transaction import atomic
|
||||||
from django.db.utils import IntegrityError
|
from django.db.utils import IntegrityError
|
||||||
@ -91,6 +92,7 @@ from authentik.stages.email.tasks import send_mails
|
|||||||
from authentik.stages.email.utils import TemplateEmailMessage
|
from authentik.stages.email.utils import TemplateEmailMessage
|
||||||
|
|
||||||
LOGGER = get_logger()
|
LOGGER = get_logger()
|
||||||
|
SessionStore: SessionBase = import_module(settings.SESSION_ENGINE).SessionStore
|
||||||
|
|
||||||
|
|
||||||
class UserGroupSerializer(ModelSerializer):
|
class UserGroupSerializer(ModelSerializer):
|
||||||
@ -774,7 +776,8 @@ class UserViewSet(UsedByMixin, ModelViewSet):
|
|||||||
if not instance.is_active:
|
if not instance.is_active:
|
||||||
sessions = AuthenticatedSession.objects.filter(user=instance)
|
sessions = AuthenticatedSession.objects.filter(user=instance)
|
||||||
session_ids = sessions.values_list("session_key", flat=True)
|
session_ids = sessions.values_list("session_key", flat=True)
|
||||||
cache.delete_many(f"{KEY_PREFIX}{session}" for session in session_ids)
|
for session in session_ids:
|
||||||
|
SessionStore(session).delete()
|
||||||
sessions.delete()
|
sessions.delete()
|
||||||
LOGGER.debug("Deleted user's sessions", user=instance.username)
|
LOGGER.debug("Deleted user's sessions", user=instance.username)
|
||||||
return response
|
return response
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
"""authentik core signals"""
|
"""authentik core signals"""
|
||||||
|
|
||||||
|
from importlib import import_module
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
from django.contrib.auth.signals import user_logged_in, user_logged_out
|
from django.contrib.auth.signals import user_logged_in, user_logged_out
|
||||||
from django.contrib.sessions.backends.cache import KEY_PREFIX
|
from django.contrib.sessions.backends.base import SessionBase
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
from django.core.signals import Signal
|
from django.core.signals import Signal
|
||||||
from django.db.models import Model
|
from django.db.models import Model
|
||||||
@ -25,6 +28,7 @@ password_changed = Signal()
|
|||||||
login_failed = Signal()
|
login_failed = Signal()
|
||||||
|
|
||||||
LOGGER = get_logger()
|
LOGGER = get_logger()
|
||||||
|
SessionStore: SessionBase = import_module(settings.SESSION_ENGINE).SessionStore
|
||||||
|
|
||||||
|
|
||||||
@receiver(post_save, sender=Application)
|
@receiver(post_save, sender=Application)
|
||||||
@ -60,8 +64,7 @@ def user_logged_out_session(sender, request: HttpRequest, user: User, **_):
|
|||||||
@receiver(pre_delete, sender=AuthenticatedSession)
|
@receiver(pre_delete, sender=AuthenticatedSession)
|
||||||
def authenticated_session_delete(sender: type[Model], instance: "AuthenticatedSession", **_):
|
def authenticated_session_delete(sender: type[Model], instance: "AuthenticatedSession", **_):
|
||||||
"""Delete session when authenticated session is deleted"""
|
"""Delete session when authenticated session is deleted"""
|
||||||
cache_key = f"{KEY_PREFIX}{instance.session_key}"
|
SessionStore(instance.session_key).delete()
|
||||||
cache.delete(cache_key)
|
|
||||||
|
|
||||||
|
|
||||||
@receiver(pre_save)
|
@receiver(pre_save)
|
||||||
|
23
website/docs/security/cves/CVE-2025-29928.md
Normal file
23
website/docs/security/cves/CVE-2025-29928.md
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
# CVE-2025-29928
|
||||||
|
|
||||||
|
## Deletion of sessions did not revoke sessions when using database session storage
|
||||||
|
|
||||||
|
### Summary
|
||||||
|
|
||||||
|
When authentik was configured to use the database for session storage (which is a non-default setting), deleting sessions via the Web Interface or the API would not revoke the session and the session holder would continue to have access to authentik.
|
||||||
|
|
||||||
|
This also affects automatic session deletion when a user is set to inactive or a user is deleted.
|
||||||
|
|
||||||
|
### Patches
|
||||||
|
|
||||||
|
authentik 2025.2.3 and 2024.12.4 fix this issue.
|
||||||
|
|
||||||
|
### Workarounds
|
||||||
|
|
||||||
|
Switching to the cache-based session storage until the authentik instance can be upgraded is recommended.
|
||||||
|
|
||||||
|
### For more information
|
||||||
|
|
||||||
|
If you have any questions or comments about this advisory:
|
||||||
|
|
||||||
|
- Email us at [security@goauthentik.io](mailto:security@goauthentik.io).
|
@ -704,6 +704,11 @@ export default {
|
|||||||
type: "category",
|
type: "category",
|
||||||
label: "CVEs",
|
label: "CVEs",
|
||||||
items: [
|
items: [
|
||||||
|
{
|
||||||
|
type: "category",
|
||||||
|
label: "2024",
|
||||||
|
items: ["security/cves/CVE-2025-29928"],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
type: "category",
|
type: "category",
|
||||||
label: "2024",
|
label: "2024",
|
||||||
|
Reference in New Issue
Block a user