events: improve handling creation of events with non-pickleable objects
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
parent
93fee5f0e5
commit
3251bdc220
|
@ -1,7 +1,6 @@
|
||||||
"""authentik events models"""
|
"""authentik events models"""
|
||||||
import time
|
import time
|
||||||
from collections import Counter
|
from collections import Counter
|
||||||
from copy import deepcopy
|
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from inspect import currentframe
|
from inspect import currentframe
|
||||||
from smtplib import SMTPException
|
from smtplib import SMTPException
|
||||||
|
@ -211,7 +210,7 @@ class Event(SerializerModel, ExpiringModel):
|
||||||
current = currentframe()
|
current = currentframe()
|
||||||
parent = current.f_back
|
parent = current.f_back
|
||||||
app = parent.f_globals["__name__"]
|
app = parent.f_globals["__name__"]
|
||||||
cleaned_kwargs = cleanse_dict(sanitize_dict(deepcopy(kwargs)))
|
cleaned_kwargs = cleanse_dict(sanitize_dict(kwargs))
|
||||||
event = Event(action=action, app=app, context=cleaned_kwargs)
|
event = Event(action=action, app=app, context=cleaned_kwargs)
|
||||||
return event
|
return event
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
"""event utilities"""
|
"""event utilities"""
|
||||||
import re
|
import re
|
||||||
|
from copy import copy
|
||||||
from dataclasses import asdict, is_dataclass
|
from dataclasses import asdict, is_dataclass
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from types import GeneratorType
|
from types import GeneratorType
|
||||||
|
@ -87,9 +88,15 @@ def sanitize_item(value: Any) -> Any:
|
||||||
"""Sanitize a single item, ensure it is JSON parsable"""
|
"""Sanitize a single item, ensure it is JSON parsable"""
|
||||||
if is_dataclass(value):
|
if is_dataclass(value):
|
||||||
# Because asdict calls `copy.deepcopy(obj)` on everything that's not tuple/dict,
|
# Because asdict calls `copy.deepcopy(obj)` on everything that's not tuple/dict,
|
||||||
# and deepcopy doesn't work with HttpRequests (neither django nor rest_framework).
|
# and deepcopy doesn't work with HttpRequest (neither django nor rest_framework).
|
||||||
|
# (more specifically doesn't work with ResolverMatch)
|
||||||
|
# rest_framework's custom Request class makes this more complicated as it also holds a
|
||||||
|
# thread lock.
|
||||||
|
# Since this class is mainly used for Events which already hold the http request context
|
||||||
|
# we just remove the http_request from the shallow policy request
|
||||||
# Currently, the only dataclass that actually holds an http request is a PolicyRequest
|
# Currently, the only dataclass that actually holds an http request is a PolicyRequest
|
||||||
if isinstance(value, PolicyRequest):
|
if isinstance(value, PolicyRequest) and value.http_request is not None:
|
||||||
|
value: PolicyRequest = copy(value)
|
||||||
value.http_request = None
|
value.http_request = None
|
||||||
value = asdict(value)
|
value = asdict(value)
|
||||||
if isinstance(value, dict):
|
if isinstance(value, dict):
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
from django.contrib.auth.models import AnonymousUser
|
from django.contrib.auth.models import AnonymousUser
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
from django.test import RequestFactory, TestCase
|
from django.test import RequestFactory, TestCase
|
||||||
|
from django.urls import resolve, reverse
|
||||||
from guardian.shortcuts import get_anonymous_user
|
from guardian.shortcuts import get_anonymous_user
|
||||||
|
|
||||||
from authentik.core.models import Application, Group, User
|
from authentik.core.models import Application, Group, User
|
||||||
|
@ -129,8 +130,9 @@ class TestPolicyProcess(TestCase):
|
||||||
)
|
)
|
||||||
binding = PolicyBinding(policy=policy, target=Application.objects.create(name="test"))
|
binding = PolicyBinding(policy=policy, target=Application.objects.create(name="test"))
|
||||||
|
|
||||||
http_request = self.factory.get("/")
|
http_request = self.factory.get(reverse("authentik_core:impersonate-end"))
|
||||||
http_request.user = self.user
|
http_request.user = self.user
|
||||||
|
http_request.resolver_match = resolve(reverse("authentik_core:impersonate-end"))
|
||||||
|
|
||||||
request = PolicyRequest(self.user)
|
request = PolicyRequest(self.user)
|
||||||
request.set_http_request(http_request)
|
request.set_http_request(http_request)
|
||||||
|
|
Reference in a new issue