*: add validator to ensure JSON Fields only receive dicts
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
parent
a0daaabfde
commit
4f27a97e10
|
@ -1,13 +1,17 @@
|
|||
"""Groups API Viewset"""
|
||||
from rest_framework.fields import JSONField
|
||||
from rest_framework.serializers import ModelSerializer
|
||||
from rest_framework.viewsets import ModelViewSet
|
||||
|
||||
from authentik.core.api.utils import is_dict
|
||||
from authentik.core.models import Group
|
||||
|
||||
|
||||
class GroupSerializer(ModelSerializer):
|
||||
"""Group Serializer"""
|
||||
|
||||
attributes = JSONField(validators=[is_dict])
|
||||
|
||||
class Meta:
|
||||
|
||||
model = Group
|
||||
|
|
|
@ -4,7 +4,7 @@ from django.utils.http import urlencode
|
|||
from drf_yasg.utils import swagger_auto_schema, swagger_serializer_method
|
||||
from guardian.utils import get_anonymous_user
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.fields import CharField, SerializerMethodField
|
||||
from rest_framework.fields import CharField, JSONField, SerializerMethodField
|
||||
from rest_framework.request import Request
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.serializers import BooleanField, ModelSerializer
|
||||
|
@ -12,7 +12,7 @@ from rest_framework.viewsets import ModelViewSet
|
|||
|
||||
from authentik.admin.api.metrics import CoordinateSerializer, get_events_per_1h
|
||||
from authentik.api.decorators import permission_required
|
||||
from authentik.core.api.utils import LinkSerializer, PassiveSerializer
|
||||
from authentik.core.api.utils import LinkSerializer, PassiveSerializer, is_dict
|
||||
from authentik.core.middleware import (
|
||||
SESSION_IMPERSONATE_ORIGINAL_USER,
|
||||
SESSION_IMPERSONATE_USER,
|
||||
|
@ -26,6 +26,7 @@ class UserSerializer(ModelSerializer):
|
|||
|
||||
is_superuser = BooleanField(read_only=True)
|
||||
avatar = CharField(read_only=True)
|
||||
attributes = JSONField(validators=[is_dict])
|
||||
|
||||
class Meta:
|
||||
|
||||
|
|
|
@ -1,7 +1,20 @@
|
|||
"""API Utilities"""
|
||||
from typing import Any
|
||||
|
||||
from django.db.models import Model
|
||||
from rest_framework.fields import CharField, IntegerField
|
||||
from rest_framework.serializers import Serializer, SerializerMethodField
|
||||
from rest_framework.serializers import (
|
||||
Serializer,
|
||||
SerializerMethodField,
|
||||
ValidationError,
|
||||
)
|
||||
|
||||
|
||||
def is_dict(value: Any):
|
||||
"""Ensure a value is a dictionary, useful for JSONFields"""
|
||||
if isinstance(value, dict):
|
||||
return
|
||||
raise ValidationError("Value must be a dictionary.")
|
||||
|
||||
|
||||
class PassiveSerializer(Serializer):
|
||||
|
|
15
authentik/core/tests/test_api_utils.py
Normal file
15
authentik/core/tests/test_api_utils.py
Normal file
|
@ -0,0 +1,15 @@
|
|||
"""Test API Utils"""
|
||||
from rest_framework.exceptions import ValidationError
|
||||
from rest_framework.test import APITestCase
|
||||
|
||||
from authentik.core.api.utils import is_dict
|
||||
|
||||
|
||||
class TestAPIUtils(APITestCase):
|
||||
"""Test API Utils"""
|
||||
|
||||
def test_is_dict(self):
|
||||
"""Test is_dict"""
|
||||
self.assertIsNone(is_dict({}))
|
||||
with self.assertRaises(ValidationError):
|
||||
is_dict("foo")
|
|
@ -8,14 +8,14 @@ from rest_framework.serializers import JSONField, ModelSerializer
|
|||
from rest_framework.viewsets import ModelViewSet
|
||||
|
||||
from authentik.core.api.providers import ProviderSerializer
|
||||
from authentik.core.api.utils import PassiveSerializer
|
||||
from authentik.core.api.utils import PassiveSerializer, is_dict
|
||||
from authentik.outposts.models import Outpost, default_outpost_config
|
||||
|
||||
|
||||
class OutpostSerializer(ModelSerializer):
|
||||
"""Outpost Serializer"""
|
||||
|
||||
_config = JSONField()
|
||||
_config = JSONField(validators=[is_dict])
|
||||
providers_obj = ProviderSerializer(source="providers", many=True, read_only=True)
|
||||
|
||||
class Meta:
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
from rest_framework.fields import BooleanField, CharField, JSONField, ListField
|
||||
from rest_framework.relations import PrimaryKeyRelatedField
|
||||
|
||||
from authentik.core.api.utils import PassiveSerializer
|
||||
from authentik.core.api.utils import PassiveSerializer, is_dict
|
||||
from authentik.core.models import User
|
||||
|
||||
|
||||
|
@ -10,7 +10,7 @@ class PolicyTestSerializer(PassiveSerializer):
|
|||
"""Test policy execution for a user with context"""
|
||||
|
||||
user = PrimaryKeyRelatedField(queryset=User.objects.all())
|
||||
context = JSONField(required=False)
|
||||
context = JSONField(required=False, validators=[is_dict])
|
||||
|
||||
|
||||
class PolicyTestResultSerializer(PassiveSerializer):
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
"""Invitation Stage API Views"""
|
||||
from rest_framework.fields import JSONField
|
||||
from rest_framework.serializers import ModelSerializer
|
||||
from rest_framework.viewsets import ModelViewSet
|
||||
|
||||
from authentik.core.api.utils import is_dict
|
||||
from authentik.flows.api.stages import StageSerializer
|
||||
from authentik.stages.invitation.models import Invitation, InvitationStage
|
||||
|
||||
|
@ -27,6 +29,8 @@ class InvitationStageViewSet(ModelViewSet):
|
|||
class InvitationSerializer(ModelSerializer):
|
||||
"""Invitation Serializer"""
|
||||
|
||||
fixed_data = JSONField(validators=[is_dict])
|
||||
|
||||
class Meta:
|
||||
|
||||
model = Invitation
|
||||
|
|
|
@ -142,7 +142,9 @@ class TestInvitationsAPI(APITestCase):
|
|||
def test_invite_create(self):
|
||||
"""Test Invitations creation endpoint"""
|
||||
response = self.client.post(
|
||||
reverse("authentik_api:invitation-list"), {"identifier": "test-token"}
|
||||
reverse("authentik_api:invitation-list"),
|
||||
{"identifier": "test-token", "fixed_data": {}},
|
||||
format="json"
|
||||
)
|
||||
self.assertEqual(response.status_code, 201)
|
||||
self.assertEqual(Invitation.objects.first().created_by, self.user)
|
||||
|
|
Reference in a new issue