Compare commits
4 Commits
trustchain
...
sources/ld
Author | SHA1 | Date |
---|---|---|
Jens Langhammer | 2a6479062f | |
Jens Langhammer | 52463b8f96 | |
Jens Langhammer | 330f639a7e | |
Jens Langhammer | 85ea4651e4 |
|
@ -0,0 +1,41 @@
|
||||||
|
# Generated by Django 4.2.5 on 2023-09-27 10:44
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
("authentik_core", "0031_alter_user_type"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="GroupSourceConnection",
|
||||||
|
fields=[
|
||||||
|
(
|
||||||
|
"id",
|
||||||
|
models.AutoField(
|
||||||
|
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("created", models.DateTimeField(auto_now_add=True)),
|
||||||
|
("last_updated", models.DateTimeField(auto_now=True)),
|
||||||
|
(
|
||||||
|
"group",
|
||||||
|
models.ForeignKey(
|
||||||
|
on_delete=django.db.models.deletion.CASCADE, to="authentik_core.group"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"source",
|
||||||
|
models.ForeignKey(
|
||||||
|
on_delete=django.db.models.deletion.CASCADE, to="authentik_core.source"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
"unique_together": {("group", "source")},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
|
@ -575,6 +575,23 @@ class UserSourceConnection(SerializerModel, CreatedUpdatedModel):
|
||||||
unique_together = (("user", "source"),)
|
unique_together = (("user", "source"),)
|
||||||
|
|
||||||
|
|
||||||
|
class GroupSourceConnection(SerializerModel, CreatedUpdatedModel):
|
||||||
|
"""Connection between Group and Source."""
|
||||||
|
|
||||||
|
group = models.ForeignKey(Group, on_delete=models.CASCADE)
|
||||||
|
source = models.ForeignKey(Source, on_delete=models.CASCADE)
|
||||||
|
|
||||||
|
objects = InheritanceManager()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def serializer(self) -> type[Serializer]:
|
||||||
|
"""Get serializer for this model"""
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
unique_together = (("group", "source"),)
|
||||||
|
|
||||||
|
|
||||||
class ExpiringModel(models.Model):
|
class ExpiringModel(models.Model):
|
||||||
"""Base Model which can expire, and is automatically cleaned up."""
|
"""Base Model which can expire, and is automatically cleaned up."""
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
"""Property mapping API Views"""
|
||||||
|
from django_filters.filters import AllValuesMultipleFilter
|
||||||
|
from django_filters.filterset import FilterSet
|
||||||
|
from drf_spectacular.types import OpenApiTypes
|
||||||
|
from drf_spectacular.utils import extend_schema_field
|
||||||
|
from rest_framework.viewsets import ModelViewSet
|
||||||
|
|
||||||
|
from authentik.core.api.propertymappings import PropertyMappingSerializer
|
||||||
|
from authentik.core.api.used_by import UsedByMixin
|
||||||
|
from authentik.sources.ldap.models import LDAPPropertyMapping
|
||||||
|
|
||||||
|
|
||||||
|
class LDAPPropertyMappingSerializer(PropertyMappingSerializer):
|
||||||
|
"""LDAP PropertyMapping Serializer"""
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = LDAPPropertyMapping
|
||||||
|
fields = PropertyMappingSerializer.Meta.fields + [
|
||||||
|
"object_field",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class LDAPPropertyMappingFilter(FilterSet):
|
||||||
|
"""Filter for LDAPPropertyMapping"""
|
||||||
|
|
||||||
|
managed = extend_schema_field(OpenApiTypes.STR)(AllValuesMultipleFilter(field_name="managed"))
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = LDAPPropertyMapping
|
||||||
|
fields = "__all__"
|
||||||
|
|
||||||
|
|
||||||
|
class LDAPPropertyMappingViewSet(UsedByMixin, ModelViewSet):
|
||||||
|
"""LDAP PropertyMapping Viewset"""
|
||||||
|
|
||||||
|
queryset = LDAPPropertyMapping.objects.all()
|
||||||
|
serializer_class = LDAPPropertyMappingSerializer
|
||||||
|
filterset_class = LDAPPropertyMappingFilter
|
||||||
|
search_fields = ["name"]
|
||||||
|
ordering = ["name"]
|
|
@ -0,0 +1,32 @@
|
||||||
|
"""LDAP Source Serializer"""
|
||||||
|
from django_filters.rest_framework import DjangoFilterBackend
|
||||||
|
from rest_framework.filters import OrderingFilter, SearchFilter
|
||||||
|
from rest_framework.viewsets import ModelViewSet
|
||||||
|
|
||||||
|
from authentik.api.authorization import OwnerFilter, OwnerSuperuserPermissions
|
||||||
|
from authentik.core.api.sources import UserSourceConnectionSerializer
|
||||||
|
from authentik.core.api.used_by import UsedByMixin
|
||||||
|
from authentik.sources.ldap.models import LDAPUserSourceConnection
|
||||||
|
|
||||||
|
|
||||||
|
class LDAPUserSourceConnectionSerializer(UserSourceConnectionSerializer):
|
||||||
|
"""LDAP Source Serializer"""
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = LDAPUserSourceConnection
|
||||||
|
fields = ["pk", "user", "source", "unique_identifier"]
|
||||||
|
extra_kwargs = {
|
||||||
|
"access_token": {"write_only": True},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class LDAPUserSourceConnectionViewSet(UsedByMixin, ModelViewSet):
|
||||||
|
"""Source Viewset"""
|
||||||
|
|
||||||
|
queryset = LDAPUserSourceConnection.objects.all()
|
||||||
|
serializer_class = LDAPUserSourceConnectionSerializer
|
||||||
|
filterset_fields = ["source__slug"]
|
||||||
|
search_fields = ["source__slug"]
|
||||||
|
permission_classes = [OwnerSuperuserPermissions]
|
||||||
|
filter_backends = [OwnerFilter, DjangoFilterBackend, OrderingFilter, SearchFilter]
|
||||||
|
ordering = ["source__slug"]
|
|
@ -1,10 +1,7 @@
|
||||||
"""Source API Views"""
|
"""Source API Views"""
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from django_filters.filters import AllValuesMultipleFilter
|
from drf_spectacular.utils import extend_schema, inline_serializer
|
||||||
from django_filters.filterset import FilterSet
|
|
||||||
from drf_spectacular.types import OpenApiTypes
|
|
||||||
from drf_spectacular.utils import extend_schema, extend_schema_field, inline_serializer
|
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action
|
||||||
from rest_framework.exceptions import ValidationError
|
from rest_framework.exceptions import ValidationError
|
||||||
from rest_framework.fields import DictField, ListField
|
from rest_framework.fields import DictField, ListField
|
||||||
|
@ -14,12 +11,11 @@ from rest_framework.response import Response
|
||||||
from rest_framework.viewsets import ModelViewSet
|
from rest_framework.viewsets import ModelViewSet
|
||||||
|
|
||||||
from authentik.admin.api.tasks import TaskSerializer
|
from authentik.admin.api.tasks import TaskSerializer
|
||||||
from authentik.core.api.propertymappings import PropertyMappingSerializer
|
|
||||||
from authentik.core.api.sources import SourceSerializer
|
from authentik.core.api.sources import SourceSerializer
|
||||||
from authentik.core.api.used_by import UsedByMixin
|
from authentik.core.api.used_by import UsedByMixin
|
||||||
from authentik.crypto.models import CertificateKeyPair
|
from authentik.crypto.models import CertificateKeyPair
|
||||||
from authentik.events.monitored_tasks import TaskInfo
|
from authentik.events.monitored_tasks import TaskInfo
|
||||||
from authentik.sources.ldap.models import LDAPPropertyMapping, LDAPSource
|
from authentik.sources.ldap.models import LDAPSource
|
||||||
from authentik.sources.ldap.tasks import SYNC_CLASSES
|
from authentik.sources.ldap.tasks import SYNC_CLASSES
|
||||||
|
|
||||||
|
|
||||||
|
@ -154,33 +150,3 @@ class LDAPSourceViewSet(UsedByMixin, ModelViewSet):
|
||||||
obj.pop("raw_dn", None)
|
obj.pop("raw_dn", None)
|
||||||
all_objects[class_name].append(obj)
|
all_objects[class_name].append(obj)
|
||||||
return Response(data=all_objects)
|
return Response(data=all_objects)
|
||||||
|
|
||||||
|
|
||||||
class LDAPPropertyMappingSerializer(PropertyMappingSerializer):
|
|
||||||
"""LDAP PropertyMapping Serializer"""
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = LDAPPropertyMapping
|
|
||||||
fields = PropertyMappingSerializer.Meta.fields + [
|
|
||||||
"object_field",
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
class LDAPPropertyMappingFilter(FilterSet):
|
|
||||||
"""Filter for LDAPPropertyMapping"""
|
|
||||||
|
|
||||||
managed = extend_schema_field(OpenApiTypes.STR)(AllValuesMultipleFilter(field_name="managed"))
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = LDAPPropertyMapping
|
|
||||||
fields = "__all__"
|
|
||||||
|
|
||||||
|
|
||||||
class LDAPPropertyMappingViewSet(UsedByMixin, ModelViewSet):
|
|
||||||
"""LDAP PropertyMapping Viewset"""
|
|
||||||
|
|
||||||
queryset = LDAPPropertyMapping.objects.all()
|
|
||||||
serializer_class = LDAPPropertyMappingSerializer
|
|
||||||
filterset_class = LDAPPropertyMappingFilter
|
|
||||||
search_fields = ["name"]
|
|
||||||
ordering = ["name"]
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
# Generated by Django 4.2.5 on 2023-09-27 10:44
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
("authentik_core", "0032_groupsourceconnection"),
|
||||||
|
("authentik_sources_ldap", "0003_ldapsource_client_certificate_ldapsource_sni_and_more"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="LDAPGroupSourceConnection",
|
||||||
|
fields=[
|
||||||
|
(
|
||||||
|
"groupsourceconnection_ptr",
|
||||||
|
models.OneToOneField(
|
||||||
|
auto_created=True,
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
parent_link=True,
|
||||||
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
to="authentik_core.groupsourceconnection",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("unique_identifier", models.TextField(unique=True)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
"verbose_name": "LDAP Group Source Connection",
|
||||||
|
"verbose_name_plural": "LDAP Group Source Connections",
|
||||||
|
},
|
||||||
|
bases=("authentik_core.groupsourceconnection",),
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="LDAPUserSourceConnection",
|
||||||
|
fields=[
|
||||||
|
(
|
||||||
|
"usersourceconnection_ptr",
|
||||||
|
models.OneToOneField(
|
||||||
|
auto_created=True,
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
parent_link=True,
|
||||||
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
to="authentik_core.usersourceconnection",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("unique_identifier", models.TextField(unique=True)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
"verbose_name": "LDAP User Source Connection",
|
||||||
|
"verbose_name_plural": "LDAP User Source Connections",
|
||||||
|
},
|
||||||
|
bases=("authentik_core.usersourceconnection",),
|
||||||
|
),
|
||||||
|
]
|
|
@ -10,7 +10,13 @@ from ldap3 import ALL, NONE, RANDOM, Connection, Server, ServerPool, Tls
|
||||||
from ldap3.core.exceptions import LDAPInsufficientAccessRightsResult, LDAPSchemaError
|
from ldap3.core.exceptions import LDAPInsufficientAccessRightsResult, LDAPSchemaError
|
||||||
from rest_framework.serializers import Serializer
|
from rest_framework.serializers import Serializer
|
||||||
|
|
||||||
from authentik.core.models import Group, PropertyMapping, Source
|
from authentik.core.models import (
|
||||||
|
Group,
|
||||||
|
GroupSourceConnection,
|
||||||
|
PropertyMapping,
|
||||||
|
Source,
|
||||||
|
UserSourceConnection,
|
||||||
|
)
|
||||||
from authentik.crypto.models import CertificateKeyPair
|
from authentik.crypto.models import CertificateKeyPair
|
||||||
from authentik.lib.config import CONFIG
|
from authentik.lib.config import CONFIG
|
||||||
from authentik.lib.models import DomainlessURLValidator
|
from authentik.lib.models import DomainlessURLValidator
|
||||||
|
@ -113,7 +119,7 @@ class LDAPSource(Source):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def serializer(self) -> type[Serializer]:
|
def serializer(self) -> type[Serializer]:
|
||||||
from authentik.sources.ldap.api import LDAPSourceSerializer
|
from authentik.sources.ldap.api.sources import LDAPSourceSerializer
|
||||||
|
|
||||||
return LDAPSourceSerializer
|
return LDAPSourceSerializer
|
||||||
|
|
||||||
|
@ -202,7 +208,7 @@ class LDAPPropertyMapping(PropertyMapping):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def serializer(self) -> type[Serializer]:
|
def serializer(self) -> type[Serializer]:
|
||||||
from authentik.sources.ldap.api import LDAPPropertyMappingSerializer
|
from authentik.sources.ldap.api.property_mappings import LDAPPropertyMappingSerializer
|
||||||
|
|
||||||
return LDAPPropertyMappingSerializer
|
return LDAPPropertyMappingSerializer
|
||||||
|
|
||||||
|
@ -212,3 +218,35 @@ class LDAPPropertyMapping(PropertyMapping):
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _("LDAP Property Mapping")
|
verbose_name = _("LDAP Property Mapping")
|
||||||
verbose_name_plural = _("LDAP Property Mappings")
|
verbose_name_plural = _("LDAP Property Mappings")
|
||||||
|
|
||||||
|
|
||||||
|
class LDAPUserSourceConnection(UserSourceConnection):
|
||||||
|
"""Connection between an authentik user and an LDAP source."""
|
||||||
|
|
||||||
|
unique_identifier = models.TextField(unique=True)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def serializer(self) -> Serializer:
|
||||||
|
from authentik.sources.ldap.api.source_connections import LDAPUserSourceConnectionSerializer
|
||||||
|
|
||||||
|
return LDAPUserSourceConnectionSerializer
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = _("LDAP User Source Connection")
|
||||||
|
verbose_name_plural = _("LDAP User Source Connections")
|
||||||
|
|
||||||
|
|
||||||
|
class LDAPGroupSourceConnection(GroupSourceConnection):
|
||||||
|
"""Connection between an authentik group and an LDAP source."""
|
||||||
|
|
||||||
|
unique_identifier = models.TextField(unique=True)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def serializer(self) -> Serializer:
|
||||||
|
from authentik.sources.ldap.api.source_connections import LDAPUserSourceConnectionSerializer
|
||||||
|
|
||||||
|
return LDAPUserSourceConnectionSerializer
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = _("LDAP Group Source Connection")
|
||||||
|
verbose_name_plural = _("LDAP Group Source Connections")
|
||||||
|
|
|
@ -7,6 +7,7 @@ from ldap3 import ALL_ATTRIBUTES, ALL_OPERATIONAL_ATTRIBUTES, SUBTREE
|
||||||
|
|
||||||
from authentik.core.models import Group
|
from authentik.core.models import Group
|
||||||
from authentik.events.models import Event, EventAction
|
from authentik.events.models import Event, EventAction
|
||||||
|
from authentik.sources.ldap.models import LDAPGroupSourceConnection
|
||||||
from authentik.sources.ldap.sync.base import LDAP_UNIQUENESS, BaseLDAPSynchronizer
|
from authentik.sources.ldap.sync.base import LDAP_UNIQUENESS, BaseLDAPSynchronizer
|
||||||
|
|
||||||
|
|
||||||
|
@ -63,7 +64,13 @@ class GroupLDAPSynchronizer(BaseLDAPSynchronizer):
|
||||||
},
|
},
|
||||||
defaults,
|
defaults,
|
||||||
)
|
)
|
||||||
self._logger.debug("Created group with attributes", **defaults)
|
LDAPGroupSourceConnection.objects.update_or_create(
|
||||||
|
defaults={
|
||||||
|
"unique_identifier": uniq,
|
||||||
|
},
|
||||||
|
source=self._source,
|
||||||
|
group=ak_group,
|
||||||
|
)
|
||||||
except (IntegrityError, FieldError, TypeError, AttributeError) as exc:
|
except (IntegrityError, FieldError, TypeError, AttributeError) as exc:
|
||||||
Event.new(
|
Event.new(
|
||||||
EventAction.CONFIGURATION_ERROR,
|
EventAction.CONFIGURATION_ERROR,
|
||||||
|
|
|
@ -7,6 +7,7 @@ from ldap3 import ALL_ATTRIBUTES, ALL_OPERATIONAL_ATTRIBUTES, SUBTREE
|
||||||
|
|
||||||
from authentik.core.models import User
|
from authentik.core.models import User
|
||||||
from authentik.events.models import Event, EventAction
|
from authentik.events.models import Event, EventAction
|
||||||
|
from authentik.sources.ldap.models import LDAPUserSourceConnection
|
||||||
from authentik.sources.ldap.sync.base import LDAP_UNIQUENESS, BaseLDAPSynchronizer
|
from authentik.sources.ldap.sync.base import LDAP_UNIQUENESS, BaseLDAPSynchronizer
|
||||||
from authentik.sources.ldap.sync.vendor.freeipa import FreeIPA
|
from authentik.sources.ldap.sync.vendor.freeipa import FreeIPA
|
||||||
from authentik.sources.ldap.sync.vendor.ms_ad import MicrosoftActiveDirectory
|
from authentik.sources.ldap.sync.vendor.ms_ad import MicrosoftActiveDirectory
|
||||||
|
@ -58,6 +59,13 @@ class UserLDAPSynchronizer(BaseLDAPSynchronizer):
|
||||||
ak_user, created = self.update_or_create_attributes(
|
ak_user, created = self.update_or_create_attributes(
|
||||||
User, {f"attributes__{LDAP_UNIQUENESS}": uniq}, defaults
|
User, {f"attributes__{LDAP_UNIQUENESS}": uniq}, defaults
|
||||||
)
|
)
|
||||||
|
LDAPUserSourceConnection.objects.update_or_create(
|
||||||
|
defaults={
|
||||||
|
"unique_identifier": uniq,
|
||||||
|
},
|
||||||
|
source=self._source,
|
||||||
|
user=ak_user,
|
||||||
|
)
|
||||||
except (IntegrityError, FieldError, TypeError, AttributeError) as exc:
|
except (IntegrityError, FieldError, TypeError, AttributeError) as exc:
|
||||||
Event.new(
|
Event.new(
|
||||||
EventAction.CONFIGURATION_ERROR,
|
EventAction.CONFIGURATION_ERROR,
|
||||||
|
@ -72,6 +80,7 @@ class UserLDAPSynchronizer(BaseLDAPSynchronizer):
|
||||||
else:
|
else:
|
||||||
self._logger.debug("Synced User", user=ak_user.username, created=created)
|
self._logger.debug("Synced User", user=ak_user.username, created=created)
|
||||||
user_count += 1
|
user_count += 1
|
||||||
|
# TODO: Optimise vendor sync to not create a new connection
|
||||||
MicrosoftActiveDirectory(self._source).sync(attributes, ak_user, created)
|
MicrosoftActiveDirectory(self._source).sync(attributes, ak_user, created)
|
||||||
FreeIPA(self._source).sync(attributes, ak_user, created)
|
FreeIPA(self._source).sync(attributes, ak_user, created)
|
||||||
return user_count
|
return user_count
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
from rest_framework.test import APITestCase
|
from rest_framework.test import APITestCase
|
||||||
|
|
||||||
from authentik.lib.generators import generate_key
|
from authentik.lib.generators import generate_key
|
||||||
from authentik.sources.ldap.api import LDAPSourceSerializer
|
from authentik.sources.ldap.api.sources import LDAPSourceSerializer
|
||||||
from authentik.sources.ldap.models import LDAPSource
|
from authentik.sources.ldap.models import LDAPSource
|
||||||
|
|
||||||
LDAP_PASSWORD = generate_key()
|
LDAP_PASSWORD = generate_key()
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
"""API URLs"""
|
"""API URLs"""
|
||||||
from authentik.sources.ldap.api import LDAPPropertyMappingViewSet, LDAPSourceViewSet
|
from authentik.sources.ldap.api.property_mappings import LDAPPropertyMappingViewSet
|
||||||
|
from authentik.sources.ldap.api.source_connections import LDAPUserSourceConnectionViewSet
|
||||||
|
from authentik.sources.ldap.api.sources import LDAPSourceViewSet
|
||||||
|
|
||||||
api_urlpatterns = [
|
api_urlpatterns = [
|
||||||
("propertymappings/ldap", LDAPPropertyMappingViewSet),
|
("propertymappings/ldap", LDAPPropertyMappingViewSet),
|
||||||
|
("sources/user_connections/ldap", LDAPUserSourceConnectionViewSet),
|
||||||
("sources/ldap", LDAPSourceViewSet),
|
("sources/ldap", LDAPSourceViewSet),
|
||||||
]
|
]
|
||||||
|
|
|
@ -68,7 +68,7 @@ class OAuthSource(Source):
|
||||||
# we're using Type[] instead of type[] here since type[] interferes with the property above
|
# we're using Type[] instead of type[] here since type[] interferes with the property above
|
||||||
@property
|
@property
|
||||||
def serializer(self) -> Type[Serializer]:
|
def serializer(self) -> Type[Serializer]:
|
||||||
from authentik.sources.oauth.api.source import OAuthSourceSerializer
|
from authentik.sources.oauth.api.sources import OAuthSourceSerializer
|
||||||
|
|
||||||
return OAuthSourceSerializer
|
return OAuthSourceSerializer
|
||||||
|
|
||||||
|
@ -234,7 +234,7 @@ class UserOAuthSourceConnection(UserSourceConnection):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def serializer(self) -> Serializer:
|
def serializer(self) -> Serializer:
|
||||||
from authentik.sources.oauth.api.source_connection import (
|
from authentik.sources.oauth.api.source_connections import (
|
||||||
UserOAuthSourceConnectionSerializer,
|
UserOAuthSourceConnectionSerializer,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ from django.test import TestCase
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from requests_mock import Mocker
|
from requests_mock import Mocker
|
||||||
|
|
||||||
from authentik.sources.oauth.api.source import OAuthSourceSerializer
|
from authentik.sources.oauth.api.sources import OAuthSourceSerializer
|
||||||
from authentik.sources.oauth.models import OAuthSource
|
from authentik.sources.oauth.models import OAuthSource
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
|
|
||||||
from django.urls import path
|
from django.urls import path
|
||||||
|
|
||||||
from authentik.sources.oauth.api.source import OAuthSourceViewSet
|
from authentik.sources.oauth.api.source_connections import UserOAuthSourceConnectionViewSet
|
||||||
from authentik.sources.oauth.api.source_connection import UserOAuthSourceConnectionViewSet
|
from authentik.sources.oauth.api.sources import OAuthSourceViewSet
|
||||||
from authentik.sources.oauth.types.registry import RequestKind
|
from authentik.sources.oauth.types.registry import RequestKind
|
||||||
from authentik.sources.oauth.views.dispatcher import DispatcherView
|
from authentik.sources.oauth.views.dispatcher import DispatcherView
|
||||||
|
|
||||||
|
|
Reference in New Issue