diff --git a/authentik/events/middleware.py b/authentik/events/middleware.py index a3ff3c8b70..826db6b736 100644 --- a/authentik/events/middleware.py +++ b/authentik/events/middleware.py @@ -35,6 +35,7 @@ IGNORED_MODELS = tuple( _CTX_OVERWRITE_USER = ContextVar[User | None]("authentik_events_log_overwrite_user", default=None) _CTX_IGNORE = ContextVar[bool]("authentik_events_log_ignore", default=False) +_CTX_REQUEST = ContextVar[HttpRequest | None]("authentik_events_log_request", default=None) def should_log_model(model: Model) -> bool: @@ -149,11 +150,13 @@ class AuditMiddleware: m2m_changed.disconnect(dispatch_uid=request.request_id) def __call__(self, request: HttpRequest) -> HttpResponse: + _CTX_REQUEST.set(request) self.connect(request) response = self.get_response(request) self.disconnect(request) + _CTX_REQUEST.set(None) return response def process_exception(self, request: HttpRequest, exception: Exception): @@ -167,7 +170,7 @@ class AuditMiddleware: thread = EventNewThread( EventAction.SUSPICIOUS_REQUEST, request, - message=str(exception), + message=exception_to_string(exception), ) thread.run() elif before_send({}, {"exc_info": (None, exception, None)}) is not None: @@ -192,6 +195,8 @@ class AuditMiddleware: return if _CTX_IGNORE.get(): return + if request.request_id != _CTX_REQUEST.get().request_id: + return user = self.get_user(request) action = EventAction.MODEL_CREATED if created else EventAction.MODEL_UPDATED @@ -205,6 +210,8 @@ class AuditMiddleware: return if _CTX_IGNORE.get(): return + if request.request_id != _CTX_REQUEST.get().request_id: + return user = self.get_user(request) EventNewThread( @@ -230,6 +237,8 @@ class AuditMiddleware: return if _CTX_IGNORE.get(): return + if request.request_id != _CTX_REQUEST.get().request_id: + return user = self.get_user(request) EventNewThread( diff --git a/authentik/events/models.py b/authentik/events/models.py index 92d934c55b..3289c957e5 100644 --- a/authentik/events/models.py +++ b/authentik/events/models.py @@ -238,6 +238,8 @@ class Event(SerializerModel, ExpiringModel): "args": cleanse_dict(QueryDict(request.META.get("QUERY_STRING", ""))), "user_agent": request.META.get("HTTP_USER_AGENT", ""), } + if hasattr(request, "request_id"): + self.context["http_request"]["request_id"] = request.request_id # Special case for events created during flow execution # since they keep the http query within a wrapped query if QS_QUERY in self.context["http_request"]["args"]: diff --git a/authentik/stages/authenticator_validate/tests/test_duo.py b/authentik/stages/authenticator_validate/tests/test_duo.py index bc76442c8b..dbfe52559a 100644 --- a/authentik/stages/authenticator_validate/tests/test_duo.py +++ b/authentik/stages/authenticator_validate/tests/test_duo.py @@ -8,6 +8,7 @@ from django.urls import reverse from rest_framework.exceptions import ValidationError from authentik.brands.utils import get_brand_for_request +from authentik.core.middleware import RESPONSE_HEADER_ID from authentik.core.tests.utils import create_test_admin_user, create_test_flow from authentik.events.models import Event, EventAction from authentik.flows.models import FlowDesignation, FlowStageBinding @@ -186,6 +187,7 @@ class AuthenticatorValidateStageDuoTests(FlowTestCase): "method": "GET", "path": f"/api/v3/flows/executor/{flow.slug}/", "user_agent": "", + "request_id": response[RESPONSE_HEADER_ID], }, }, )