sources: allow uuid or slug to be used for retrieving a source (2024.12 fix) (#12772)
sources: allow uuid or slug to be used for retrieving a source Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
37
authentik/lib/api.py
Normal file
37
authentik/lib/api.py
Normal file
@ -0,0 +1,37 @@
|
||||
from collections.abc import Callable, Sequence
|
||||
from typing import Self
|
||||
from uuid import UUID
|
||||
|
||||
from django.db.models import Model, Q, QuerySet, UUIDField
|
||||
from django.shortcuts import get_object_or_404
|
||||
|
||||
|
||||
class MultipleFieldLookupMixin:
|
||||
"""Helper mixin class to add support for multiple lookup_fields.
|
||||
`lookup_fields` needs to be set which specifies the actual fields to query, `lookup_field`
|
||||
is only used to generate the URL."""
|
||||
|
||||
lookup_field: str
|
||||
lookup_fields: str | Sequence[str]
|
||||
|
||||
get_queryset: Callable[[Self], QuerySet]
|
||||
filter_queryset: Callable[[Self, QuerySet], QuerySet]
|
||||
|
||||
def get_object(self):
|
||||
queryset: QuerySet = self.get_queryset()
|
||||
queryset = self.filter_queryset(queryset)
|
||||
if isinstance(self.lookup_fields, str):
|
||||
self.lookup_fields = [self.lookup_fields]
|
||||
query = Q()
|
||||
model: Model = queryset.model
|
||||
for field in self.lookup_fields:
|
||||
field_inst = model._meta.get_field(field)
|
||||
# Sanity check, if the field we're filtering again, only apply the filter if
|
||||
# our value looks like a UUID
|
||||
if isinstance(field_inst, UUIDField):
|
||||
try:
|
||||
UUID(self.kwargs[self.lookup_field])
|
||||
except ValueError:
|
||||
continue
|
||||
query |= Q(**{field: self.kwargs[self.lookup_field]})
|
||||
return get_object_or_404(queryset, query)
|
||||
@ -13,6 +13,7 @@ from authentik.core.api.sources import SourceSerializer
|
||||
from authentik.core.api.used_by import UsedByMixin
|
||||
from authentik.core.api.utils import PassiveSerializer
|
||||
from authentik.events.api.tasks import SystemTaskSerializer
|
||||
from authentik.lib.api import MultipleFieldLookupMixin
|
||||
from authentik.sources.kerberos.models import KerberosSource
|
||||
from authentik.sources.kerberos.tasks import CACHE_KEY_STATUS
|
||||
|
||||
@ -59,12 +60,13 @@ class KerberosSyncStatusSerializer(PassiveSerializer):
|
||||
tasks = SystemTaskSerializer(many=True, read_only=True)
|
||||
|
||||
|
||||
class KerberosSourceViewSet(UsedByMixin, ModelViewSet):
|
||||
class KerberosSourceViewSet(MultipleFieldLookupMixin, UsedByMixin, ModelViewSet):
|
||||
"""Kerberos Source Viewset"""
|
||||
|
||||
queryset = KerberosSource.objects.all()
|
||||
serializer_class = KerberosSourceSerializer
|
||||
lookup_field = "slug"
|
||||
lookup_fields = ["slug", "pbm_uuid"]
|
||||
filterset_fields = [
|
||||
"name",
|
||||
"slug",
|
||||
|
||||
@ -18,6 +18,7 @@ from authentik.core.api.property_mappings import PropertyMappingFilterSet, Prope
|
||||
from authentik.core.api.sources import SourceSerializer
|
||||
from authentik.core.api.used_by import UsedByMixin
|
||||
from authentik.crypto.models import CertificateKeyPair
|
||||
from authentik.lib.api import MultipleFieldLookupMixin
|
||||
from authentik.lib.sync.outgoing.api import SyncStatusSerializer
|
||||
from authentik.sources.ldap.models import LDAPSource, LDAPSourcePropertyMapping
|
||||
from authentik.sources.ldap.tasks import CACHE_KEY_STATUS, SYNC_CLASSES
|
||||
@ -103,12 +104,13 @@ class LDAPSourceSerializer(SourceSerializer):
|
||||
extra_kwargs = {"bind_password": {"write_only": True}}
|
||||
|
||||
|
||||
class LDAPSourceViewSet(UsedByMixin, ModelViewSet):
|
||||
class LDAPSourceViewSet(MultipleFieldLookupMixin, UsedByMixin, ModelViewSet):
|
||||
"""LDAP Source Viewset"""
|
||||
|
||||
queryset = LDAPSource.objects.all()
|
||||
serializer_class = LDAPSourceSerializer
|
||||
lookup_field = "slug"
|
||||
lookup_fields = ["slug", "pbm_uuid"]
|
||||
filterset_fields = [
|
||||
"name",
|
||||
"slug",
|
||||
|
||||
@ -16,6 +16,7 @@ from rest_framework.viewsets import ModelViewSet
|
||||
from authentik.core.api.sources import SourceSerializer
|
||||
from authentik.core.api.used_by import UsedByMixin
|
||||
from authentik.core.api.utils import PassiveSerializer
|
||||
from authentik.lib.api import MultipleFieldLookupMixin
|
||||
from authentik.lib.utils.http import get_http_session
|
||||
from authentik.sources.oauth.models import OAuthSource
|
||||
from authentik.sources.oauth.types.registry import SourceType, registry
|
||||
@ -170,12 +171,13 @@ class OAuthSourceFilter(FilterSet):
|
||||
]
|
||||
|
||||
|
||||
class OAuthSourceViewSet(UsedByMixin, ModelViewSet):
|
||||
class OAuthSourceViewSet(MultipleFieldLookupMixin, UsedByMixin, ModelViewSet):
|
||||
"""Source Viewset"""
|
||||
|
||||
queryset = OAuthSource.objects.all()
|
||||
serializer_class = OAuthSourceSerializer
|
||||
lookup_field = "slug"
|
||||
lookup_fields = ["slug", "pbm_uuid"]
|
||||
filterset_class = OAuthSourceFilter
|
||||
search_fields = ["name", "slug"]
|
||||
ordering = ["name"]
|
||||
|
||||
@ -18,6 +18,7 @@ from authentik.core.api.used_by import UsedByMixin
|
||||
from authentik.core.api.utils import PassiveSerializer
|
||||
from authentik.flows.challenge import RedirectChallenge
|
||||
from authentik.flows.views.executor import to_stage_response
|
||||
from authentik.lib.api import MultipleFieldLookupMixin
|
||||
from authentik.rbac.decorators import permission_required
|
||||
from authentik.sources.plex.models import PlexSource, UserPlexSourceConnection
|
||||
from authentik.sources.plex.plex import PlexAuth, PlexSourceFlowManager
|
||||
@ -45,12 +46,13 @@ class PlexTokenRedeemSerializer(PassiveSerializer):
|
||||
plex_token = CharField()
|
||||
|
||||
|
||||
class PlexSourceViewSet(UsedByMixin, ModelViewSet):
|
||||
class PlexSourceViewSet(MultipleFieldLookupMixin, UsedByMixin, ModelViewSet):
|
||||
"""Plex source Viewset"""
|
||||
|
||||
queryset = PlexSource.objects.all()
|
||||
serializer_class = PlexSourceSerializer
|
||||
lookup_field = "slug"
|
||||
lookup_fields = ["slug", "pbm_uuid"]
|
||||
filterset_fields = [
|
||||
"name",
|
||||
"slug",
|
||||
|
||||
@ -9,6 +9,7 @@ from rest_framework.viewsets import ModelViewSet
|
||||
|
||||
from authentik.core.api.sources import SourceSerializer
|
||||
from authentik.core.api.used_by import UsedByMixin
|
||||
from authentik.lib.api import MultipleFieldLookupMixin
|
||||
from authentik.providers.saml.api.providers import SAMLMetadataSerializer
|
||||
from authentik.sources.saml.models import SAMLSource
|
||||
from authentik.sources.saml.processors.metadata import MetadataProcessor
|
||||
@ -37,12 +38,13 @@ class SAMLSourceSerializer(SourceSerializer):
|
||||
]
|
||||
|
||||
|
||||
class SAMLSourceViewSet(UsedByMixin, ModelViewSet):
|
||||
class SAMLSourceViewSet(MultipleFieldLookupMixin, UsedByMixin, ModelViewSet):
|
||||
"""SAMLSource Viewset"""
|
||||
|
||||
queryset = SAMLSource.objects.all()
|
||||
serializer_class = SAMLSourceSerializer
|
||||
lookup_field = "slug"
|
||||
lookup_fields = ["slug", "pbm_uuid"]
|
||||
filterset_fields = [
|
||||
"name",
|
||||
"slug",
|
||||
|
||||
@ -7,6 +7,7 @@ from rest_framework.viewsets import ModelViewSet
|
||||
from authentik.core.api.sources import SourceSerializer
|
||||
from authentik.core.api.tokens import TokenSerializer
|
||||
from authentik.core.api.used_by import UsedByMixin
|
||||
from authentik.lib.api import MultipleFieldLookupMixin
|
||||
from authentik.sources.scim.models import SCIMSource
|
||||
|
||||
|
||||
@ -47,12 +48,13 @@ class SCIMSourceSerializer(SourceSerializer):
|
||||
]
|
||||
|
||||
|
||||
class SCIMSourceViewSet(UsedByMixin, ModelViewSet):
|
||||
class SCIMSourceViewSet(MultipleFieldLookupMixin, UsedByMixin, ModelViewSet):
|
||||
"""SCIMSource Viewset"""
|
||||
|
||||
queryset = SCIMSource.objects.all()
|
||||
serializer_class = SCIMSourceSerializer
|
||||
lookup_field = "slug"
|
||||
lookup_fields = ["slug", "pbm_uuid"]
|
||||
filterset_fields = ["name", "slug"]
|
||||
search_fields = ["name", "slug", "token__identifier", "token__user__username"]
|
||||
ordering = ["name"]
|
||||
|
||||
@ -4,7 +4,7 @@ import { DualSelectPair } from "@goauthentik/elements/ak-dual-select/types";
|
||||
import { OAuthSource, SourcesApi } from "@goauthentik/api";
|
||||
|
||||
const sourceToSelect = (source: OAuthSource) => [
|
||||
source.slug,
|
||||
source.pk,
|
||||
`${source.name} (${source.slug})`,
|
||||
source.name,
|
||||
source,
|
||||
|
||||
Reference in New Issue
Block a user