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:
Jens L 2022-05-29 18:58:54 +02:00 committed by GitHub
parent 612163b82f
commit fb25b28976
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 31 additions and 2 deletions

View file

@ -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,

View file

@ -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"