core: db sessions (#2979)
* use db session backend Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * root: wrap session cookie in JWT and add useful claims Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * fix compatibility with tests Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * use standard session key for writing in sessions too Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
parent
612163b82f
commit
fb25b28976
|
@ -1,4 +1,5 @@
|
|||
"""Dynamically set SameSite depending if the upstream connection is TLS or not"""
|
||||
from hashlib import sha512
|
||||
from time import time
|
||||
from typing import Callable
|
||||
|
||||
|
@ -10,11 +11,14 @@ from django.http.request import HttpRequest
|
|||
from django.http.response import HttpResponse
|
||||
from django.utils.cache import patch_vary_headers
|
||||
from django.utils.http import http_date
|
||||
from jwt import PyJWTError, decode, encode
|
||||
from structlog.stdlib import get_logger
|
||||
|
||||
from authentik.lib.utils.http import get_client_ip
|
||||
|
||||
LOGGER = get_logger("authentik.asgi")
|
||||
ACR_AUTHENTIK_SESSION = "goauthentik.io/core/default"
|
||||
SIGNING_HASH = sha512(settings.SECRET_KEY.encode()).hexdigest()
|
||||
|
||||
|
||||
class SessionMiddleware(UpstreamSessionMiddleware):
|
||||
|
@ -35,6 +39,18 @@ class SessionMiddleware(UpstreamSessionMiddleware):
|
|||
return True
|
||||
return False
|
||||
|
||||
def process_request(self, request):
|
||||
session_jwt = request.COOKIES.get(settings.SESSION_COOKIE_NAME)
|
||||
# We need to support the standard django format of just a session key
|
||||
# for testing setups, where the session is directly set
|
||||
session_key = session_jwt if settings.TEST else None
|
||||
try:
|
||||
session_payload = decode(session_jwt, SIGNING_HASH, algorithms=["HS256"])
|
||||
session_key = session_payload["sid"]
|
||||
except (KeyError, PyJWTError):
|
||||
pass
|
||||
request.session = self.SessionStore(session_key)
|
||||
|
||||
def process_response(self, request: HttpRequest, response: HttpResponse) -> HttpResponse:
|
||||
"""
|
||||
If request.session was modified, or if the configuration is to save the
|
||||
|
@ -82,9 +98,21 @@ class SessionMiddleware(UpstreamSessionMiddleware):
|
|||
"request completed. The user may have logged "
|
||||
"out in a concurrent request, for example."
|
||||
)
|
||||
payload = {
|
||||
"sid": request.session.session_key,
|
||||
"iss": "authentik",
|
||||
"sub": "anonymous",
|
||||
"authenticated": request.user.is_authenticated,
|
||||
"acr": ACR_AUTHENTIK_SESSION,
|
||||
}
|
||||
if request.user.is_authenticated:
|
||||
payload["sub"] = request.user.uid
|
||||
value = encode(payload=payload, key=SIGNING_HASH)
|
||||
if settings.TEST:
|
||||
value = request.session.session_key
|
||||
response.set_cookie(
|
||||
settings.SESSION_COOKIE_NAME,
|
||||
request.session.session_key,
|
||||
value,
|
||||
max_age=max_age,
|
||||
expires=expires,
|
||||
domain=settings.SESSION_COOKIE_DOMAIN,
|
||||
|
|
|
@ -216,7 +216,8 @@ CACHES = {
|
|||
DJANGO_REDIS_SCAN_ITERSIZE = 1000
|
||||
DJANGO_REDIS_IGNORE_EXCEPTIONS = True
|
||||
DJANGO_REDIS_LOG_IGNORED_EXCEPTIONS = True
|
||||
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
|
||||
SESSION_ENGINE = "django.contrib.sessions.backends.cached_db"
|
||||
SESSION_SERIALIZER = "django.contrib.sessions.serializers.PickleSerializer"
|
||||
SESSION_CACHE_ALIAS = "default"
|
||||
# Configured via custom SessionMiddleware
|
||||
# SESSION_COOKIE_SAMESITE = "None"
|
||||
|
|
Reference in a new issue