diff --git a/authentik/core/api/utils.py b/authentik/core/api/utils.py index b2afcb5383..85ffde9160 100644 --- a/authentik/core/api/utils.py +++ b/authentik/core/api/utils.py @@ -2,6 +2,7 @@ from typing import Any +from django.db import models from django.db.models import Model from drf_spectacular.extensions import OpenApiSerializerFieldExtension from drf_spectacular.plumbing import build_basic_type @@ -30,7 +31,27 @@ def is_dict(value: Any): raise ValidationError("Value must be a dictionary, and not have any duplicate keys.") +class JSONDictField(JSONField): + """JSON Field which only allows dictionaries""" + + default_validators = [is_dict] + + +class JSONExtension(OpenApiSerializerFieldExtension): + """Generate API Schema for JSON fields as""" + + target_class = "authentik.core.api.utils.JSONDictField" + + def map_serializer_field(self, auto_schema, direction): + return build_basic_type(OpenApiTypes.OBJECT) + + class ModelSerializer(BaseModelSerializer): + + # By default, JSON fields we have are used to store dictionaries + serializer_field_mapping = BaseModelSerializer.serializer_field_mapping.copy() + serializer_field_mapping[models.JSONField] = JSONDictField + def create(self, validated_data): instance = super().create(validated_data) @@ -71,21 +92,6 @@ class ModelSerializer(BaseModelSerializer): return instance -class JSONDictField(JSONField): - """JSON Field which only allows dictionaries""" - - default_validators = [is_dict] - - -class JSONExtension(OpenApiSerializerFieldExtension): - """Generate API Schema for JSON fields as""" - - target_class = "authentik.core.api.utils.JSONDictField" - - def map_serializer_field(self, auto_schema, direction): - return build_basic_type(OpenApiTypes.OBJECT) - - class PassiveSerializer(Serializer): """Base serializer class which doesn't implement create/update methods""" diff --git a/authentik/tenants/api/settings.py b/authentik/tenants/api/settings.py index d8d1624b8a..9fa4934a7c 100644 --- a/authentik/tenants/api/settings.py +++ b/authentik/tenants/api/settings.py @@ -1,6 +1,7 @@ """Serializer for tenants models""" from django_tenants.utils import get_public_schema_name +from rest_framework.fields import JSONField from rest_framework.generics import RetrieveUpdateAPIView from rest_framework.permissions import SAFE_METHODS @@ -12,6 +13,8 @@ from authentik.tenants.models import Tenant class SettingsSerializer(ModelSerializer): """Settings Serializer""" + footer_links = JSONField(required=False) + class Meta: model = Tenant fields = [ diff --git a/schema.yml b/schema.yml index 2aef9f924b..5dd2c9ab3a 100644 --- a/schema.yml +++ b/schema.yml @@ -41338,7 +41338,9 @@ components: app: type: string format: uuid - attributes: {} + attributes: + type: object + additionalProperties: {} required: - app - name @@ -41353,7 +41355,9 @@ components: app: type: string format: uuid - attributes: {} + attributes: + type: object + additionalProperties: {} required: - app - name @@ -41942,7 +41946,9 @@ components: friendly_name: type: string nullable: true - credentials: {} + credentials: + type: object + additionalProperties: {} required: - component - credentials @@ -41972,7 +41978,9 @@ components: type: string nullable: true minLength: 1 - credentials: {} + credentials: + type: object + additionalProperties: {} required: - credentials - name @@ -42777,7 +42785,9 @@ components: path: type: string default: '' - context: {} + context: + type: object + additionalProperties: {} last_applied: type: string format: date-time @@ -42797,6 +42807,8 @@ components: type: string readOnly: true metadata: + type: object + additionalProperties: {} readOnly: true content: type: string @@ -42818,7 +42830,9 @@ components: path: type: string default: '' - context: {} + context: + type: object + additionalProperties: {} enabled: type: boolean content: @@ -42898,7 +42912,9 @@ components: type: string format: uuid description: Certificates used for client authentication. - attributes: {} + attributes: + type: object + additionalProperties: {} required: - brand_uuid - domain @@ -42968,7 +42984,9 @@ components: type: string format: uuid description: Certificates used for client authentication. - attributes: {} + attributes: + type: object + additionalProperties: {} required: - domain Cache: @@ -44609,7 +44627,9 @@ components: $ref: '#/components/schemas/ProtocolEnum' host: type: string - settings: {} + settings: + type: object + additionalProperties: {} property_mappings: type: array items: @@ -44680,7 +44700,9 @@ components: host: type: string minLength: 1 - settings: {} + settings: + type: object + additionalProperties: {} property_mappings: type: array items: @@ -44744,12 +44766,16 @@ components: format: uuid readOnly: true title: Event uuid - user: {} + user: + type: object + additionalProperties: {} action: $ref: '#/components/schemas/EventActions' app: type: string - context: {} + context: + type: object + additionalProperties: {} client_ip: type: string nullable: true @@ -44760,7 +44786,9 @@ components: expires: type: string format: date-time - brand: {} + brand: + type: object + additionalProperties: {} required: - action - app @@ -44905,13 +44933,17 @@ components: type: object description: Event Serializer properties: - user: {} + user: + type: object + additionalProperties: {} action: $ref: '#/components/schemas/EventActions' app: type: string minLength: 1 - context: {} + context: + type: object + additionalProperties: {} client_ip: type: string nullable: true @@ -44919,7 +44951,9 @@ components: expires: type: string format: date-time - brand: {} + brand: + type: object + additionalProperties: {} required: - action - app @@ -45894,7 +45928,9 @@ components: type: string format: email maxLength: 254 - credentials: {} + credentials: + type: object + additionalProperties: {} scopes: type: string exclude_users_service_account: @@ -45945,6 +45981,8 @@ components: provider: type: integer attributes: + type: object + additionalProperties: {} readOnly: true required: - attributes @@ -46059,7 +46097,9 @@ components: format: email minLength: 1 maxLength: 254 - credentials: {} + credentials: + type: object + additionalProperties: {} scopes: type: string minLength: 1 @@ -46104,6 +46144,8 @@ components: provider: type: integer attributes: + type: object + additionalProperties: {} readOnly: true required: - attributes @@ -47432,6 +47474,8 @@ components: description: Return internal model name readOnly: true kubeconfig: + type: object + additionalProperties: {} description: Paste your kubeconfig here. authentik will automatically use the currently selected context. verify_ssl: @@ -47456,6 +47500,8 @@ components: description: If enabled, use the local connection. Required Docker socket/Kubernetes Integration kubeconfig: + type: object + additionalProperties: {} description: Paste your kubeconfig here. authentik will automatically use the currently selected context. verify_ssl: @@ -48392,6 +48438,8 @@ components: provider: type: integer attributes: + type: object + additionalProperties: {} readOnly: true required: - attributes @@ -48548,6 +48596,8 @@ components: provider: type: integer attributes: + type: object + additionalProperties: {} readOnly: true required: - attributes @@ -49460,7 +49510,9 @@ components: type: string oidc_jwks_url: type: string - oidc_jwks: {} + oidc_jwks: + type: object + additionalProperties: {} authorization_code_auth_method: allOf: - $ref: '#/components/schemas/AuthorizationCodeAuthMethodEnum' @@ -49634,7 +49686,9 @@ components: type: string oidc_jwks_url: type: string - oidc_jwks: {} + oidc_jwks: + type: object + additionalProperties: {} authorization_code_auth_method: allOf: - $ref: '#/components/schemas/AuthorizationCodeAuthMethodEnum' @@ -52319,7 +52373,9 @@ components: app: type: string format: uuid - attributes: {} + attributes: + type: object + additionalProperties: {} PatchedApplicationRequest: type: object description: Application Serializer @@ -52471,7 +52527,9 @@ components: type: string nullable: true minLength: 1 - credentials: {} + credentials: + type: object + additionalProperties: {} PatchedAuthenticatorSMSStageRequest: type: object description: AuthenticatorSMSStage Serializer @@ -52658,7 +52716,9 @@ components: path: type: string default: '' - context: {} + context: + type: object + additionalProperties: {} enabled: type: boolean content: @@ -52729,7 +52789,9 @@ components: type: string format: uuid description: Certificates used for client authentication. - attributes: {} + attributes: + type: object + additionalProperties: {} PatchedCaptchaStageRequest: type: object description: CaptchaStage Serializer @@ -53005,7 +53067,9 @@ components: host: type: string minLength: 1 - settings: {} + settings: + type: object + additionalProperties: {} property_mappings: type: array items: @@ -53057,13 +53121,17 @@ components: type: object description: Event Serializer properties: - user: {} + user: + type: object + additionalProperties: {} action: $ref: '#/components/schemas/EventActions' app: type: string minLength: 1 - context: {} + context: + type: object + additionalProperties: {} client_ip: type: string nullable: true @@ -53071,7 +53139,9 @@ components: expires: type: string format: date-time - brand: {} + brand: + type: object + additionalProperties: {} PatchedExpressionPolicyRequest: type: object description: Group Membership Policy Serializer @@ -53254,7 +53324,9 @@ components: format: email minLength: 1 maxLength: 254 - credentials: {} + credentials: + type: object + additionalProperties: {} scopes: type: string minLength: 1 @@ -53638,6 +53710,8 @@ components: description: If enabled, use the local connection. Required Docker socket/Kubernetes Integration kubeconfig: + type: object + additionalProperties: {} description: Paste your kubeconfig here. authentik will automatically use the currently selected context. verify_ssl: @@ -54221,7 +54295,9 @@ components: type: string oidc_jwks_url: type: string - oidc_jwks: {} + oidc_jwks: + type: object + additionalProperties: {} authorization_code_auth_method: allOf: - $ref: '#/components/schemas/AuthorizationCodeAuthMethodEnum' @@ -54700,7 +54776,9 @@ components: items: type: string format: uuid - settings: {} + settings: + type: object + additionalProperties: {} connection_expiry: type: string minLength: 1 @@ -55157,7 +55235,9 @@ components: source: type: string format: uuid - attributes: {} + attributes: + type: object + additionalProperties: {} PatchedSCIMSourcePropertyMappingRequest: type: object description: SCIMSourcePropertyMapping Serializer @@ -55218,7 +55298,9 @@ components: source: type: string format: uuid - attributes: {} + attributes: + type: object + additionalProperties: {} PatchedSMSDeviceRequest: type: object description: Serializer for sms authenticator devices @@ -55305,9 +55387,7 @@ components: minimum: 0 description: Reputation cannot increase higher than this value. Zero or positive. - footer_links: - description: The option configures the footer links on the flow executor - pages. + footer_links: {} gdpr_compliance: type: boolean description: When enabled, all the events caused by a user will be deleted @@ -57119,7 +57199,9 @@ components: type: string description: Return internal model name readOnly: true - settings: {} + settings: + type: object + additionalProperties: {} outpost_set: type: array items: @@ -57167,7 +57249,9 @@ components: items: type: string format: uuid - settings: {} + settings: + type: object + additionalProperties: {} connection_expiry: type: string minLength: 1 @@ -57577,8 +57661,12 @@ components: type: string ip: type: string - ip_geo_data: {} - ip_asn_data: {} + ip_geo_data: + type: object + additionalProperties: {} + ip_asn_data: + type: object + additionalProperties: {} score: type: integer maximum: 9223372036854775807 @@ -58651,6 +58739,8 @@ components: provider: type: integer attributes: + type: object + additionalProperties: {} readOnly: true required: - attributes @@ -58741,6 +58831,8 @@ components: provider: type: integer attributes: + type: object + additionalProperties: {} readOnly: true required: - attributes @@ -58855,7 +58947,9 @@ components: source: type: string format: uuid - attributes: {} + attributes: + type: object + additionalProperties: {} required: - group - group_obj @@ -58874,7 +58968,9 @@ components: source: type: string format: uuid - attributes: {} + attributes: + type: object + additionalProperties: {} required: - group - id @@ -58993,7 +59089,9 @@ components: source: type: string format: uuid - attributes: {} + attributes: + type: object + additionalProperties: {} required: - id - source @@ -59011,7 +59109,9 @@ components: source: type: string format: uuid - attributes: {} + attributes: + type: object + additionalProperties: {} required: - id - source @@ -59404,9 +59504,7 @@ components: minimum: 0 description: Reputation cannot increase higher than this value. Zero or positive. - footer_links: - description: The option configures the footer links on the flow executor - pages. + footer_links: {} gdpr_compliance: type: boolean description: When enabled, all the events caused by a user will be deleted @@ -59458,9 +59556,7 @@ components: minimum: 0 description: Reputation cannot increase higher than this value. Zero or positive. - footer_links: - description: The option configures the footer links on the flow executor - pages. + footer_links: {} gdpr_compliance: type: boolean description: When enabled, all the events caused by a user will be deleted diff --git a/web/src/admin/events/EventMap.ts b/web/src/admin/events/EventMap.ts index b482f7ec07..17fdbe546b 100644 --- a/web/src/admin/events/EventMap.ts +++ b/web/src/admin/events/EventMap.ts @@ -92,7 +92,7 @@ export class EventMap extends AKElement { // Re-add them this.events?.results .filter((event) => { - if (!Object.hasOwn(event.context, "geo")) { + if (!Object.hasOwn(event.context || {}, "geo")) { return false; } const geo = (event as EventWithContext).context.geo;