events: fix missing model_* events when not directly authenticated (#7588)
* events: fix missing model_* events when not directly authenticated Signed-off-by: Jens Langhammer <jens@goauthentik.io> * defer accessing database Signed-off-by: Jens Langhammer <jens@goauthentik.io> --------- Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
parent
51908f6060
commit
31ef91900b
|
@ -93,21 +93,30 @@ class AuditMiddleware:
|
||||||
of models"""
|
of models"""
|
||||||
|
|
||||||
get_response: Callable[[HttpRequest], HttpResponse]
|
get_response: Callable[[HttpRequest], HttpResponse]
|
||||||
|
anonymous_user: User = None
|
||||||
|
|
||||||
def __init__(self, get_response: Callable[[HttpRequest], HttpResponse]):
|
def __init__(self, get_response: Callable[[HttpRequest], HttpResponse]):
|
||||||
self.get_response = get_response
|
self.get_response = get_response
|
||||||
|
|
||||||
|
def _ensure_fallback_user(self):
|
||||||
|
"""Defer fetching anonymous user until we have to"""
|
||||||
|
if self.anonymous_user:
|
||||||
|
return
|
||||||
|
from guardian.shortcuts import get_anonymous_user
|
||||||
|
|
||||||
|
self.anonymous_user = get_anonymous_user()
|
||||||
|
|
||||||
def connect(self, request: HttpRequest):
|
def connect(self, request: HttpRequest):
|
||||||
"""Connect signal for automatic logging"""
|
"""Connect signal for automatic logging"""
|
||||||
if not hasattr(request, "user"):
|
self._ensure_fallback_user()
|
||||||
return
|
user = getattr(request, "user", self.anonymous_user)
|
||||||
if not getattr(request.user, "is_authenticated", False):
|
if not user.is_authenticated:
|
||||||
return
|
user = self.anonymous_user
|
||||||
if not hasattr(request, "request_id"):
|
if not hasattr(request, "request_id"):
|
||||||
return
|
return
|
||||||
post_save_handler = partial(self.post_save_handler, user=request.user, request=request)
|
post_save_handler = partial(self.post_save_handler, user=user, request=request)
|
||||||
pre_delete_handler = partial(self.pre_delete_handler, user=request.user, request=request)
|
pre_delete_handler = partial(self.pre_delete_handler, user=user, request=request)
|
||||||
m2m_changed_handler = partial(self.m2m_changed_handler, user=request.user, request=request)
|
m2m_changed_handler = partial(self.m2m_changed_handler, user=user, request=request)
|
||||||
post_save.connect(
|
post_save.connect(
|
||||||
post_save_handler,
|
post_save_handler,
|
||||||
dispatch_uid=request.request_id,
|
dispatch_uid=request.request_id,
|
||||||
|
|
|
@ -6,6 +6,7 @@ from django.urls import reverse
|
||||||
from authentik.core.models import USER_ATTRIBUTE_SOURCES, Group, Source, User, UserSourceConnection
|
from authentik.core.models import USER_ATTRIBUTE_SOURCES, Group, Source, User, UserSourceConnection
|
||||||
from authentik.core.sources.stage import PLAN_CONTEXT_SOURCES_CONNECTION
|
from authentik.core.sources.stage import PLAN_CONTEXT_SOURCES_CONNECTION
|
||||||
from authentik.core.tests.utils import create_test_admin_user, create_test_flow
|
from authentik.core.tests.utils import create_test_admin_user, create_test_flow
|
||||||
|
from authentik.events.models import Event, EventAction
|
||||||
from authentik.flows.markers import StageMarker
|
from authentik.flows.markers import StageMarker
|
||||||
from authentik.flows.models import FlowStageBinding
|
from authentik.flows.models import FlowStageBinding
|
||||||
from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER, FlowPlan
|
from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER, FlowPlan
|
||||||
|
@ -58,11 +59,33 @@ class TestUserWriteStage(FlowTestCase):
|
||||||
self.assertStageRedirects(response, reverse("authentik_core:root-redirect"))
|
self.assertStageRedirects(response, reverse("authentik_core:root-redirect"))
|
||||||
user_qs = User.objects.filter(username=plan.context[PLAN_CONTEXT_PROMPT]["username"])
|
user_qs = User.objects.filter(username=plan.context[PLAN_CONTEXT_PROMPT]["username"])
|
||||||
self.assertTrue(user_qs.exists())
|
self.assertTrue(user_qs.exists())
|
||||||
self.assertTrue(user_qs.first().check_password(password))
|
user = user_qs.first()
|
||||||
self.assertEqual(
|
self.assertTrue(user.check_password(password))
|
||||||
list(user_qs.first().ak_groups.order_by("name")), [self.other_group, self.group]
|
self.assertEqual(list(user.ak_groups.order_by("name")), [self.other_group, self.group])
|
||||||
|
self.assertEqual(user.attributes, {USER_ATTRIBUTE_SOURCES: [self.source.name]})
|
||||||
|
|
||||||
|
self.assertTrue(
|
||||||
|
Event.objects.filter(
|
||||||
|
action=EventAction.MODEL_CREATED,
|
||||||
|
context__model={
|
||||||
|
"app": "authentik_core",
|
||||||
|
"model_name": "user",
|
||||||
|
"pk": user.pk,
|
||||||
|
"name": "name",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.assertTrue(
|
||||||
|
Event.objects.filter(
|
||||||
|
action=EventAction.MODEL_UPDATED,
|
||||||
|
context__model={
|
||||||
|
"app": "authentik_core",
|
||||||
|
"model_name": "user",
|
||||||
|
"pk": user.pk,
|
||||||
|
"name": "name",
|
||||||
|
},
|
||||||
|
)
|
||||||
)
|
)
|
||||||
self.assertEqual(user_qs.first().attributes, {USER_ATTRIBUTE_SOURCES: [self.source.name]})
|
|
||||||
|
|
||||||
def test_user_update(self):
|
def test_user_update(self):
|
||||||
"""Test update of existing user"""
|
"""Test update of existing user"""
|
||||||
|
|
Reference in New Issue