core: cleanup embedded outpost logging, log user for http requests

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
Jens Langhammer 2021-10-20 22:12:49 +02:00
parent 2e06786869
commit 3647633232
3 changed files with 27 additions and 7 deletions

View File

@ -9,6 +9,7 @@ from rest_framework.exceptions import AuthenticationFailed
from rest_framework.request import Request from rest_framework.request import Request
from structlog.stdlib import get_logger from structlog.stdlib import get_logger
from authentik.core.middleware import KEY_AUTH_VIA, LOCAL
from authentik.core.models import Token, TokenIntents, User from authentik.core.models import Token, TokenIntents, User
from authentik.outposts.models import Outpost from authentik.outposts.models import Outpost
@ -44,6 +45,7 @@ def bearer_auth(raw_header: bytes) -> Optional[User]:
if not user: if not user:
raise AuthenticationFailed("Token invalid/expired") raise AuthenticationFailed("Token invalid/expired")
return user return user
LOCAL.authentik[KEY_AUTH_VIA] = "api_token"
return tokens.first().user return tokens.first().user
@ -57,7 +59,7 @@ def token_secret_key(value: str) -> Optional[User]:
outposts = Outpost.objects.filter(managed=MANAGED_OUTPOST) outposts = Outpost.objects.filter(managed=MANAGED_OUTPOST)
if not outposts: if not outposts:
return None return None
LOGGER.info("Authenticating via secret_key") LOCAL.authentik[KEY_AUTH_VIA] = "secret_key"
outpost = outposts.first() outpost = outposts.first()
return outpost.user return outpost.user

View File

@ -10,6 +10,9 @@ SESSION_IMPERSONATE_USER = "authentik_impersonate_user"
SESSION_IMPERSONATE_ORIGINAL_USER = "authentik_impersonate_original_user" SESSION_IMPERSONATE_ORIGINAL_USER = "authentik_impersonate_original_user"
LOCAL = local() LOCAL = local()
RESPONSE_HEADER_ID = "X-authentik-id" RESPONSE_HEADER_ID = "X-authentik-id"
KEY_AUTH_VIA = "auth_via"
KEY_USER = "user"
INTERNAL_HEADER_PREFIX = "X-authentik-internal-"
class ImpersonateMiddleware: class ImpersonateMiddleware:
@ -50,15 +53,17 @@ class RequestIDMiddleware:
} }
response = self.get_response(request) response = self.get_response(request)
response[RESPONSE_HEADER_ID] = request.request_id response[RESPONSE_HEADER_ID] = request.request_id
del LOCAL.authentik["request_id"] if auth_via := LOCAL.authentik.get(KEY_AUTH_VIA, None):
del LOCAL.authentik["host"] response[INTERNAL_HEADER_PREFIX + KEY_AUTH_VIA] = auth_via
response[INTERNAL_HEADER_PREFIX + KEY_USER] = request.user.username
for key in list(LOCAL.authentik.keys()):
del LOCAL.authentik[key]
return response return response
# pylint: disable=unused-argument # pylint: disable=unused-argument
def structlog_add_request_id(logger: Logger, method_name: str, event_dict): def structlog_add_request_id(logger: Logger, method_name: str, event_dict: dict):
"""If threadlocal has authentik defined, add request_id to log""" """If threadlocal has authentik defined, add request_id to log"""
if hasattr(LOCAL, "authentik"): if hasattr(LOCAL, "authentik"):
event_dict["request_id"] = LOCAL.authentik.get("request_id", "") event_dict.update(LOCAL.authentik)
event_dict["host"] = LOCAL.authentik.get("host", "")
return event_dict return event_dict

View File

@ -3,7 +3,7 @@ from time import time
from structlog.stdlib import get_logger from structlog.stdlib import get_logger
from authentik.core.middleware import RESPONSE_HEADER_ID from authentik.core.middleware import INTERNAL_HEADER_PREFIX, RESPONSE_HEADER_ID
from authentik.root.asgi.types import ASGIApp, Message, Receive, Scope, Send from authentik.root.asgi.types import ASGIApp, Message, Receive, Scope, Send
ASGI_IP_HEADERS = ( ASGI_IP_HEADERS = (
@ -26,6 +26,8 @@ class ASGILogger:
content_length = 0 content_length = 0
status_code = 0 status_code = 0
request_id = "" request_id = ""
# Copy all headers starting with X-authentik-internal
copied_headers = {}
location = "" location = ""
start = time() start = time()
@ -45,9 +47,19 @@ class ASGILogger:
if message["type"] == "http.response.start": if message["type"] == "http.response.start":
response_headers = dict(message["headers"]) response_headers = dict(message["headers"])
nonlocal request_id nonlocal request_id
nonlocal copied_headers
nonlocal location nonlocal location
request_id = response_headers.get(RESPONSE_HEADER_ID.encode(), b"").decode() request_id = response_headers.get(RESPONSE_HEADER_ID.encode(), b"").decode()
location = response_headers.get(b"Location", b"").decode() location = response_headers.get(b"Location", b"").decode()
# Copy all internal headers to log, and remove them from the final response
for header in list(response_headers.keys()):
if not header.decode().startswith(INTERNAL_HEADER_PREFIX):
continue
copied_headers[
header.decode().replace(INTERNAL_HEADER_PREFIX, "")
] = response_headers[header].decode()
del response_headers[header]
message["headers"] = list(response_headers.items())
if message["type"] == "http.response.body" and not message.get("more_body", True): if message["type"] == "http.response.body" and not message.get("more_body", True):
nonlocal start nonlocal start
@ -55,6 +67,7 @@ class ASGILogger:
kwargs = {"request_id": request_id} kwargs = {"request_id": request_id}
if location != "": if location != "":
kwargs["location"] = location kwargs["location"] = location
kwargs.update(copied_headers)
self.log(scope, runtime, content_length, status_code, **kwargs) self.log(scope, runtime, content_length, status_code, **kwargs)
await send(message) await send(message)