Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

core: migrate all sessions to the database #9736

Open
wants to merge 65 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
1620176
properly override modelbackend
rissson Dec 18, 2024
12b7573
wip
rissson Dec 18, 2024
cc2ab5e
Merge branch 'main' into database-sessions
rissson Jan 27, 2025
77de597
more session migration
rissson Jan 27, 2025
aa4c9a6
start migrations
rissson Jan 27, 2025
fe635a7
migrations
rissson Jan 27, 2025
803db07
lint
rissson Jan 27, 2025
ae2dd0c
fixup
rissson Jan 27, 2025
022a9b7
further migration fixes
rissson Jan 27, 2025
ece70a6
lint
rissson Jan 27, 2025
354a48e
add uuid pk
rissson Jan 27, 2025
8c4c7ad
Merge branch 'main' into database-sessions
rissson Jan 27, 2025
561be8f
make gen
rissson Jan 27, 2025
3e4a892
fixup
rissson Jan 27, 2025
afb691e
more migration fixes
rissson Jan 27, 2025
1980e92
lifecycle/migrate: don't migrate tenants if not enabled
rissson Jan 27, 2025
04d113b
wip
rissson Jan 27, 2025
b933482
wip
rissson Jan 27, 2025
be693e3
wip
rissson Jan 27, 2025
b169196
wip
rissson Jan 27, 2025
fd2e7a1
wip
rissson Jan 27, 2025
cffaf47
wip
rissson Jan 27, 2025
f17bb66
wip
rissson Jan 27, 2025
878fe49
wip
rissson Jan 27, 2025
1de2448
wip
rissson Jan 27, 2025
78d1758
wip
rissson Jan 27, 2025
f9cc1be
wip
rissson Jan 28, 2025
857db71
Merge branch 'main' into database-sessions
rissson Jan 31, 2025
1ecf041
wip
rissson Jan 31, 2025
d0efd42
wip
rissson Jan 31, 2025
432ca9a
wip
rissson Jan 31, 2025
72f4294
finally fix imgrations
rissson Jan 31, 2025
005f22b
fix [ermissions
rissson Jan 31, 2025
355569a
Merge branch 'main' into database-sessions
rissson Feb 17, 2025
c269dfa
remove migrations
rissson Feb 17, 2025
f117e90
wip
rissson Feb 21, 2025
c582026
Merge branch 'main' into database-sessions
rissson Feb 21, 2025
41a5d62
wip
rissson Feb 21, 2025
8118aaf
wip
rissson Feb 21, 2025
8775e29
wip
rissson Feb 21, 2025
dde3f5d
fix temp migrations
rissson Feb 21, 2025
cd9c52e
custom auth middleware
rissson Feb 21, 2025
412e18f
fix tests
rissson Feb 21, 2025
15e4c78
more test fixing we ball
rissson Feb 21, 2025
a9756f0
wip
rissson Feb 21, 2025
d6e26ab
fix more tests, prefetch interesting stuff
rissson Feb 21, 2025
db762f5
more prefetch
rissson Feb 21, 2025
56560a0
Merge branch 'main' into database-sessions
rissson Feb 21, 2025
d48c26c
wip
rissson Feb 21, 2025
09b5fc4
lint
rissson Feb 21, 2025
f9fbccd
fix
rissson Feb 21, 2025
4a6e941
fix migration
rissson Feb 21, 2025
d446c2f
wip
rissson Feb 21, 2025
85cc24b
wip
rissson Feb 21, 2025
e9500f4
wip
rissson Feb 21, 2025
4a2f974
wip
rissson Feb 21, 2025
e8d0425
api tweak
rissson Feb 21, 2025
a0646cb
more fixes
rissson Feb 21, 2025
d1b6856
wip
rissson Feb 21, 2025
6fa53de
wip
rissson Feb 21, 2025
b5b68c1
wip
rissson Feb 21, 2025
17db222
Merge branch 'main' into database-sessions
rissson Feb 21, 2025
b69a1d5
Merge branch 'main' into database-sessions
rissson Feb 24, 2025
07d0751
custom asgi auth middleware
rissson Feb 27, 2025
71f9ffa
Merge branch 'main' into database-sessions
rissson Feb 27, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions authentik/blueprints/v1/importer.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
GroupSourceConnection,
PropertyMapping,
Provider,
Session,
Source,
User,
UserSourceConnection,
Expand Down Expand Up @@ -108,6 +109,7 @@ def excluded_models() -> list[type[Model]]:
Policy,
PolicyBindingModel,
# Classes that have other dependencies
Session,
AuthenticatedSession,
# Classes which are only internally managed
# FIXME: these shouldn't need to be explicitly listed, but rather based off of a mixin
Expand Down
22 changes: 15 additions & 7 deletions authentik/core/api/authenticated_sessions.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from rest_framework import mixins
from rest_framework.fields import SerializerMethodField
from rest_framework.request import Request
from rest_framework.serializers import CharField, DateTimeField, IPAddressField
from rest_framework.viewsets import GenericViewSet
from ua_parser import user_agent_parser

Expand Down Expand Up @@ -54,6 +55,11 @@
class AuthenticatedSessionSerializer(ModelSerializer):
"""AuthenticatedSession Serializer"""

expires = DateTimeField(source="session.expires", read_only=True)
last_ip = IPAddressField(source="session.last_ip", read_only=True)
last_user_agent = CharField(source="session.last_user_agent", read_only=True)
last_used = DateTimeField(source="session.last_used", read_only=True)

current = SerializerMethodField()
user_agent = SerializerMethodField()
geo_ip = SerializerMethodField()
Expand All @@ -62,19 +68,19 @@
def get_current(self, instance: AuthenticatedSession) -> bool:
"""Check if session is currently active session"""
request: Request = self.context["request"]
return request._request.session.session_key == instance.session_key
return request._request.session.session_key == instance.session.session_key

Check warning on line 71 in authentik/core/api/authenticated_sessions.py

View check run for this annotation

Codecov / codecov/patch

authentik/core/api/authenticated_sessions.py#L71

Added line #L71 was not covered by tests

def get_user_agent(self, instance: AuthenticatedSession) -> UserAgentDict:
"""Get parsed user agent"""
return user_agent_parser.Parse(instance.last_user_agent)
return user_agent_parser.Parse(instance.session.last_user_agent)

Check warning on line 75 in authentik/core/api/authenticated_sessions.py

View check run for this annotation

Codecov / codecov/patch

authentik/core/api/authenticated_sessions.py#L75

Added line #L75 was not covered by tests

def get_geo_ip(self, instance: AuthenticatedSession) -> GeoIPDict | None: # pragma: no cover
"""Get GeoIP Data"""
return GEOIP_CONTEXT_PROCESSOR.city_dict(instance.last_ip)
return GEOIP_CONTEXT_PROCESSOR.city_dict(instance.session.last_ip)

def get_asn(self, instance: AuthenticatedSession) -> ASNDict | None: # pragma: no cover
"""Get ASN Data"""
return ASN_CONTEXT_PROCESSOR.asn_dict(instance.last_ip)
return ASN_CONTEXT_PROCESSOR.asn_dict(instance.session.last_ip)

class Meta:
model = AuthenticatedSession
Expand All @@ -90,6 +96,7 @@
"last_used",
"expires",
]
extra_args = {"uuid": {"read_only": True}}


class AuthenticatedSessionViewSet(
Expand All @@ -101,9 +108,10 @@
):
"""AuthenticatedSession Viewset"""

queryset = AuthenticatedSession.objects.all()
lookup_field = "uuid"
queryset = AuthenticatedSession.objects.select_related("session").all()
serializer_class = AuthenticatedSessionSerializer
search_fields = ["user__username", "last_ip", "last_user_agent"]
filterset_fields = ["user__username", "last_ip", "last_user_agent"]
search_fields = ["user__username", "session__last_ip", "session__last_user_agent"]
filterset_fields = ["user__username", "session__last_ip", "session__last_user_agent"]
ordering = ["user__username"]
owner_field = "user"
9 changes: 2 additions & 7 deletions authentik/core/api/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@

from django.contrib.auth import update_session_auth_hash
from django.contrib.auth.models import Permission
from django.contrib.sessions.backends.cache import KEY_PREFIX
from django.core.cache import cache
from django.db.models.functions import ExtractHour
from django.db.transaction import atomic
from django.db.utils import IntegrityError
Expand Down Expand Up @@ -71,8 +69,8 @@
from authentik.core.models import (
USER_ATTRIBUTE_TOKEN_EXPIRING,
USER_PATH_SERVICE_ACCOUNT,
AuthenticatedSession,
Group,
Session,
Token,
TokenIntents,
User,
Expand Down Expand Up @@ -767,9 +765,6 @@
response = super().partial_update(request, *args, **kwargs)
instance: User = self.get_object()
if not instance.is_active:
sessions = AuthenticatedSession.objects.filter(user=instance)
session_ids = sessions.values_list("session_key", flat=True)
cache.delete_many(f"{KEY_PREFIX}{session}" for session in session_ids)
sessions.delete()
Session.objects.filter(authenticatedsession__user=instance).delete()

Check warning on line 768 in authentik/core/api/users.py

View check run for this annotation

Codecov / codecov/patch

authentik/core/api/users.py#L768

Added line #L768 was not covered by tests
LOGGER.debug("Deleted user's sessions", user=instance.username)
return response
9 changes: 9 additions & 0 deletions authentik/core/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,15 @@
self.set_method("password", request)
return user

async def aauthenticate(
self, request: HttpRequest, username: str | None, password: str | None, **kwargs: Any
) -> User | None:
user = await super().aauthenticate(request, username=username, password=password, **kwargs)
if not user:
return None
self.set_method("password", request)
return user

Check warning on line 34 in authentik/core/auth.py

View check run for this annotation

Codecov / codecov/patch

authentik/core/auth.py#L30-L34

Added lines #L30 - L34 were not covered by tests

def set_method(self, method: str, request: HttpRequest | None, **kwargs):
"""Set method data on current flow, if possbiel"""
if not request:
Expand Down
15 changes: 15 additions & 0 deletions authentik/core/management/commands/clearsessions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
"""Change user type"""

from importlib import import_module

from django.conf import settings

from authentik.tenants.management import TenantCommand


class Command(TenantCommand):
"""Delete all sessions"""

def handle_per_tenant(self, **options):
engine = import_module(settings.SESSION_ENGINE)
engine.SessionStore.clear_expired()
39 changes: 39 additions & 0 deletions authentik/core/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,14 @@

from collections.abc import Callable
from contextvars import ContextVar
from functools import partial
from uuid import uuid4

from django.contrib.auth.models import AnonymousUser
from django.core.exceptions import ImproperlyConfigured
from django.http import HttpRequest, HttpResponse
from django.utils.deprecation import MiddlewareMixin
from django.utils.functional import SimpleLazyObject
from django.utils.translation import override
from sentry_sdk.api import set_tag
from structlog.contextvars import STRUCTLOG_KEY_PREFIX
Expand All @@ -20,6 +25,40 @@
CTX_AUTH_VIA = ContextVar[str | None](STRUCTLOG_KEY_PREFIX + KEY_AUTH_VIA, default=None)


def get_user(request):
if not hasattr(request, "_cached_user"):
user = None
if (authenticated_session := request.session.get("authenticatedsession", None)) is not None:
user = authenticated_session.user
request._cached_user = user or AnonymousUser()
return request._cached_user


async def aget_user(request):
if not hasattr(request, "_cached_user"):
user = None
if (

Check warning on line 40 in authentik/core/middleware.py

View check run for this annotation

Codecov / codecov/patch

authentik/core/middleware.py#L38-L40

Added lines #L38 - L40 were not covered by tests
authenticated_session := await request.session.aget("authenticatedsession", None)
) is not None:
user = authenticated_session.user
request._cached_user = user or AnonymousUser()
return request._cached_user

Check warning on line 45 in authentik/core/middleware.py

View check run for this annotation

Codecov / codecov/patch

authentik/core/middleware.py#L43-L45

Added lines #L43 - L45 were not covered by tests


class AuthenticationMiddleware(MiddlewareMixin):
def process_request(self, request):
if not hasattr(request, "session"):
raise ImproperlyConfigured(

Check warning on line 51 in authentik/core/middleware.py

View check run for this annotation

Codecov / codecov/patch

authentik/core/middleware.py#L51

Added line #L51 was not covered by tests
"The Django authentication middleware requires session "
"middleware to be installed. Edit your MIDDLEWARE setting to "
"insert "
"'authentik.root.middleware.SessionMiddleware' before "
"'authentik.core.middleware.AuthenticationMiddleware'."
)
request.user = SimpleLazyObject(lambda: get_user(request))
request.auser = partial(aget_user, request)


class ImpersonateMiddleware:
"""Middleware to impersonate users"""

Expand Down
Loading
Loading