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"""
|
"""Dynamically set SameSite depending if the upstream connection is TLS or not"""
|
||||||
|
from hashlib import sha512
|
||||||
from time import time
|
from time import time
|
||||||
from typing import Callable
|
from typing import Callable
|
||||||
|
|
||||||
|
@ -10,11 +11,14 @@ from django.http.request import HttpRequest
|
||||||
from django.http.response import HttpResponse
|
from django.http.response import HttpResponse
|
||||||
from django.utils.cache import patch_vary_headers
|
from django.utils.cache import patch_vary_headers
|
||||||
from django.utils.http import http_date
|
from django.utils.http import http_date
|
||||||
|
from jwt import PyJWTError, decode, encode
|
||||||
from structlog.stdlib import get_logger
|
from structlog.stdlib import get_logger
|
||||||
|
|
||||||
from authentik.lib.utils.http import get_client_ip
|
from authentik.lib.utils.http import get_client_ip
|
||||||
|
|
||||||
LOGGER = get_logger("authentik.asgi")
|
LOGGER = get_logger("authentik.asgi")
|
||||||
|
ACR_AUTHENTIK_SESSION = "goauthentik.io/core/default"
|
||||||
|
SIGNING_HASH = sha512(settings.SECRET_KEY.encode()).hexdigest()
|
||||||
|
|
||||||
|
|
||||||
class SessionMiddleware(UpstreamSessionMiddleware):
|
class SessionMiddleware(UpstreamSessionMiddleware):
|
||||||
|
@ -35,6 +39,18 @@ class SessionMiddleware(UpstreamSessionMiddleware):
|
||||||
return True
|
return True
|
||||||
return False
|
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:
|
def process_response(self, request: HttpRequest, response: HttpResponse) -> HttpResponse:
|
||||||
"""
|
"""
|
||||||
If request.session was modified, or if the configuration is to save the
|
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 "
|
"request completed. The user may have logged "
|
||||||
"out in a concurrent request, for example."
|
"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(
|
response.set_cookie(
|
||||||
settings.SESSION_COOKIE_NAME,
|
settings.SESSION_COOKIE_NAME,
|
||||||
request.session.session_key,
|
value,
|
||||||
max_age=max_age,
|
max_age=max_age,
|
||||||
expires=expires,
|
expires=expires,
|
||||||
domain=settings.SESSION_COOKIE_DOMAIN,
|
domain=settings.SESSION_COOKIE_DOMAIN,
|
||||||
|
|
|
@ -216,7 +216,8 @@ CACHES = {
|
||||||
DJANGO_REDIS_SCAN_ITERSIZE = 1000
|
DJANGO_REDIS_SCAN_ITERSIZE = 1000
|
||||||
DJANGO_REDIS_IGNORE_EXCEPTIONS = True
|
DJANGO_REDIS_IGNORE_EXCEPTIONS = True
|
||||||
DJANGO_REDIS_LOG_IGNORED_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"
|
SESSION_CACHE_ALIAS = "default"
|
||||||
# Configured via custom SessionMiddleware
|
# Configured via custom SessionMiddleware
|
||||||
# SESSION_COOKIE_SAMESITE = "None"
|
# SESSION_COOKIE_SAMESITE = "None"
|
||||||
|
|
Reference in a new issue