lib/providers/sync: improve outgoing sync (#9835)
* make connection objects not updatable but allow creating with provider Signed-off-by: Jens Langhammer <jens@goauthentik.io> * save data returned from google/entra and show it in UI Signed-off-by: Jens Langhammer <jens@goauthentik.io> * pass connection object Signed-off-by: Jens Langhammer <jens@goauthentik.io> * set immutable id on user automatically Signed-off-by: Jens Langhammer <jens@goauthentik.io> * better define transient error codes Signed-off-by: Jens Langhammer <jens@goauthentik.io> * format Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix entra Signed-off-by: Jens Langhammer <jens@goauthentik.io> --------- Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
@ -1,14 +1,15 @@
|
||||
"""GoogleWorkspaceProviderGroup API Views"""
|
||||
|
||||
from rest_framework.viewsets import ModelViewSet
|
||||
from rest_framework import mixins
|
||||
from rest_framework.serializers import ModelSerializer
|
||||
from rest_framework.viewsets import GenericViewSet
|
||||
|
||||
from authentik.core.api.sources import SourceSerializer
|
||||
from authentik.core.api.used_by import UsedByMixin
|
||||
from authentik.core.api.users import UserGroupSerializer
|
||||
from authentik.enterprise.providers.google_workspace.models import GoogleWorkspaceProviderGroup
|
||||
|
||||
|
||||
class GoogleWorkspaceProviderGroupSerializer(SourceSerializer):
|
||||
class GoogleWorkspaceProviderGroupSerializer(ModelSerializer):
|
||||
"""GoogleWorkspaceProviderGroup Serializer"""
|
||||
|
||||
group_obj = UserGroupSerializer(source="group", read_only=True)
|
||||
@ -20,10 +21,20 @@ class GoogleWorkspaceProviderGroupSerializer(SourceSerializer):
|
||||
"id",
|
||||
"group",
|
||||
"group_obj",
|
||||
"provider",
|
||||
"attributes",
|
||||
]
|
||||
extra_kwargs = {"attributes": {"read_only": True}}
|
||||
|
||||
|
||||
class GoogleWorkspaceProviderGroupViewSet(UsedByMixin, ModelViewSet):
|
||||
class GoogleWorkspaceProviderGroupViewSet(
|
||||
mixins.CreateModelMixin,
|
||||
mixins.RetrieveModelMixin,
|
||||
mixins.DestroyModelMixin,
|
||||
UsedByMixin,
|
||||
mixins.ListModelMixin,
|
||||
GenericViewSet,
|
||||
):
|
||||
"""GoogleWorkspaceProviderGroup Viewset"""
|
||||
|
||||
queryset = GoogleWorkspaceProviderGroup.objects.all().select_related("group")
|
||||
|
@ -1,14 +1,15 @@
|
||||
"""GoogleWorkspaceProviderUser API Views"""
|
||||
|
||||
from rest_framework.viewsets import ModelViewSet
|
||||
from rest_framework import mixins
|
||||
from rest_framework.serializers import ModelSerializer
|
||||
from rest_framework.viewsets import GenericViewSet
|
||||
|
||||
from authentik.core.api.groups import GroupMemberSerializer
|
||||
from authentik.core.api.sources import SourceSerializer
|
||||
from authentik.core.api.used_by import UsedByMixin
|
||||
from authentik.enterprise.providers.google_workspace.models import GoogleWorkspaceProviderUser
|
||||
|
||||
|
||||
class GoogleWorkspaceProviderUserSerializer(SourceSerializer):
|
||||
class GoogleWorkspaceProviderUserSerializer(ModelSerializer):
|
||||
"""GoogleWorkspaceProviderUser Serializer"""
|
||||
|
||||
user_obj = GroupMemberSerializer(source="user", read_only=True)
|
||||
@ -20,10 +21,20 @@ class GoogleWorkspaceProviderUserSerializer(SourceSerializer):
|
||||
"id",
|
||||
"user",
|
||||
"user_obj",
|
||||
"provider",
|
||||
"attributes",
|
||||
]
|
||||
extra_kwargs = {"attributes": {"read_only": True}}
|
||||
|
||||
|
||||
class GoogleWorkspaceProviderUserViewSet(UsedByMixin, ModelViewSet):
|
||||
class GoogleWorkspaceProviderUserViewSet(
|
||||
mixins.CreateModelMixin,
|
||||
mixins.RetrieveModelMixin,
|
||||
mixins.DestroyModelMixin,
|
||||
UsedByMixin,
|
||||
mixins.ListModelMixin,
|
||||
GenericViewSet,
|
||||
):
|
||||
"""GoogleWorkspaceProviderUser Viewset"""
|
||||
|
||||
queryset = GoogleWorkspaceProviderUser.objects.all().select_related("user")
|
||||
|
@ -33,14 +33,14 @@ class GoogleWorkspaceGroupClient(
|
||||
self.mapper = PropertyMappingManager(
|
||||
self.provider.property_mappings_group.all().order_by("name").select_subclasses(),
|
||||
GoogleWorkspaceProviderMapping,
|
||||
["group", "provider", "creating"],
|
||||
["group", "provider", "connection"],
|
||||
)
|
||||
|
||||
def to_schema(self, obj: Group, creating: bool) -> dict:
|
||||
def to_schema(self, obj: Group, connection: GoogleWorkspaceProviderGroup) -> dict:
|
||||
"""Convert authentik group"""
|
||||
return super().to_schema(
|
||||
obj,
|
||||
creating,
|
||||
connection=connection,
|
||||
email=f"{slugify(obj.name)}@{self.provider.default_group_email_domain}",
|
||||
)
|
||||
|
||||
@ -61,7 +61,7 @@ class GoogleWorkspaceGroupClient(
|
||||
|
||||
def create(self, group: Group):
|
||||
"""Create group from scratch and create a connection object"""
|
||||
google_group = self.to_schema(group, True)
|
||||
google_group = self.to_schema(group, None)
|
||||
self.check_email_valid(google_group["email"])
|
||||
with transaction.atomic():
|
||||
try:
|
||||
@ -74,16 +74,22 @@ class GoogleWorkspaceGroupClient(
|
||||
self.directory_service.groups().get(groupKey=google_group["email"])
|
||||
)
|
||||
return GoogleWorkspaceProviderGroup.objects.create(
|
||||
provider=self.provider, group=group, google_id=group_data["id"]
|
||||
provider=self.provider,
|
||||
group=group,
|
||||
google_id=group_data["id"],
|
||||
attributes=group_data,
|
||||
)
|
||||
else:
|
||||
return GoogleWorkspaceProviderGroup.objects.create(
|
||||
provider=self.provider, group=group, google_id=response["id"]
|
||||
provider=self.provider,
|
||||
group=group,
|
||||
google_id=response["id"],
|
||||
attributes=response,
|
||||
)
|
||||
|
||||
def update(self, group: Group, connection: GoogleWorkspaceProviderGroup):
|
||||
"""Update existing group"""
|
||||
google_group = self.to_schema(group, False)
|
||||
google_group = self.to_schema(group, connection)
|
||||
self.check_email_valid(google_group["email"])
|
||||
try:
|
||||
return self._request(
|
||||
@ -204,4 +210,5 @@ class GoogleWorkspaceGroupClient(
|
||||
provider=self.provider,
|
||||
group=matching_authentik_group,
|
||||
google_id=google_id,
|
||||
attributes=group,
|
||||
)
|
||||
|
@ -28,15 +28,12 @@ class GoogleWorkspaceUserClient(GoogleWorkspaceSyncClient[User, GoogleWorkspaceP
|
||||
self.mapper = PropertyMappingManager(
|
||||
self.provider.property_mappings.all().order_by("name").select_subclasses(),
|
||||
GoogleWorkspaceProviderMapping,
|
||||
["provider", "creating"],
|
||||
["provider", "connection"],
|
||||
)
|
||||
|
||||
def to_schema(self, obj: User, creating: bool) -> dict:
|
||||
def to_schema(self, obj: User, connection: GoogleWorkspaceProviderUser) -> dict:
|
||||
"""Convert authentik user"""
|
||||
raw_google_user = super().to_schema(obj, creating)
|
||||
if "primaryEmail" not in raw_google_user:
|
||||
raw_google_user["primaryEmail"] = str(obj.email)
|
||||
return delete_none_values(raw_google_user)
|
||||
return delete_none_values(super().to_schema(obj, connection, primaryEmail=obj.email))
|
||||
|
||||
def delete(self, obj: User):
|
||||
"""Delete user"""
|
||||
@ -63,7 +60,7 @@ class GoogleWorkspaceUserClient(GoogleWorkspaceSyncClient[User, GoogleWorkspaceP
|
||||
|
||||
def create(self, user: User):
|
||||
"""Create user from scratch and create a connection object"""
|
||||
google_user = self.to_schema(user, True)
|
||||
google_user = self.to_schema(user, None)
|
||||
self.check_email_valid(
|
||||
google_user["primaryEmail"], *[x["address"] for x in google_user.get("emails", [])]
|
||||
)
|
||||
@ -73,18 +70,21 @@ class GoogleWorkspaceUserClient(GoogleWorkspaceSyncClient[User, GoogleWorkspaceP
|
||||
except ObjectExistsSyncException:
|
||||
# user already exists in google workspace, so we can connect them manually
|
||||
return GoogleWorkspaceProviderUser.objects.create(
|
||||
provider=self.provider, user=user, google_id=user.email
|
||||
provider=self.provider, user=user, google_id=user.email, attributes={}
|
||||
)
|
||||
except TransientSyncException as exc:
|
||||
raise exc
|
||||
else:
|
||||
return GoogleWorkspaceProviderUser.objects.create(
|
||||
provider=self.provider, user=user, google_id=response["primaryEmail"]
|
||||
provider=self.provider,
|
||||
user=user,
|
||||
google_id=response["primaryEmail"],
|
||||
attributes=response,
|
||||
)
|
||||
|
||||
def update(self, user: User, connection: GoogleWorkspaceProviderUser):
|
||||
"""Update existing user"""
|
||||
google_user = self.to_schema(user, False)
|
||||
google_user = self.to_schema(user, connection)
|
||||
self.check_email_valid(
|
||||
google_user["primaryEmail"], *[x["address"] for x in google_user.get("emails", [])]
|
||||
)
|
||||
@ -115,4 +115,5 @@ class GoogleWorkspaceUserClient(GoogleWorkspaceSyncClient[User, GoogleWorkspaceP
|
||||
provider=self.provider,
|
||||
user=matching_authentik_user,
|
||||
google_id=email,
|
||||
attributes=user,
|
||||
)
|
||||
|
@ -0,0 +1,26 @@
|
||||
# Generated by Django 5.0.6 on 2024-05-23 20:48
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
(
|
||||
"authentik_providers_google_workspace",
|
||||
"0001_squashed_0002_alter_googleworkspaceprovidergroup_options_and_more",
|
||||
),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="googleworkspaceprovidergroup",
|
||||
name="attributes",
|
||||
field=models.JSONField(default=dict),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="googleworkspaceprovideruser",
|
||||
name="attributes",
|
||||
field=models.JSONField(default=dict),
|
||||
),
|
||||
]
|
@ -153,6 +153,7 @@ class GoogleWorkspaceProviderUser(SerializerModel):
|
||||
google_id = models.TextField()
|
||||
user = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||
provider = models.ForeignKey(GoogleWorkspaceProvider, on_delete=models.CASCADE)
|
||||
attributes = models.JSONField(default=dict)
|
||||
|
||||
@property
|
||||
def serializer(self) -> type[Serializer]:
|
||||
@ -178,6 +179,7 @@ class GoogleWorkspaceProviderGroup(SerializerModel):
|
||||
google_id = models.TextField()
|
||||
group = models.ForeignKey(Group, on_delete=models.CASCADE)
|
||||
provider = models.ForeignKey(GoogleWorkspaceProvider, on_delete=models.CASCADE)
|
||||
attributes = models.JSONField(default=dict)
|
||||
|
||||
@property
|
||||
def serializer(self) -> type[Serializer]:
|
||||
|
@ -1,14 +1,15 @@
|
||||
"""MicrosoftEntraProviderGroup API Views"""
|
||||
|
||||
from rest_framework.viewsets import ModelViewSet
|
||||
from rest_framework import mixins
|
||||
from rest_framework.serializers import ModelSerializer
|
||||
from rest_framework.viewsets import GenericViewSet
|
||||
|
||||
from authentik.core.api.sources import SourceSerializer
|
||||
from authentik.core.api.used_by import UsedByMixin
|
||||
from authentik.core.api.users import UserGroupSerializer
|
||||
from authentik.enterprise.providers.microsoft_entra.models import MicrosoftEntraProviderGroup
|
||||
|
||||
|
||||
class MicrosoftEntraProviderGroupSerializer(SourceSerializer):
|
||||
class MicrosoftEntraProviderGroupSerializer(ModelSerializer):
|
||||
"""MicrosoftEntraProviderGroup Serializer"""
|
||||
|
||||
group_obj = UserGroupSerializer(source="group", read_only=True)
|
||||
@ -20,10 +21,20 @@ class MicrosoftEntraProviderGroupSerializer(SourceSerializer):
|
||||
"id",
|
||||
"group",
|
||||
"group_obj",
|
||||
"provider",
|
||||
"attributes",
|
||||
]
|
||||
extra_kwargs = {"attributes": {"read_only": True}}
|
||||
|
||||
|
||||
class MicrosoftEntraProviderGroupViewSet(UsedByMixin, ModelViewSet):
|
||||
class MicrosoftEntraProviderGroupViewSet(
|
||||
mixins.CreateModelMixin,
|
||||
mixins.RetrieveModelMixin,
|
||||
mixins.DestroyModelMixin,
|
||||
UsedByMixin,
|
||||
mixins.ListModelMixin,
|
||||
GenericViewSet,
|
||||
):
|
||||
"""MicrosoftEntraProviderGroup Viewset"""
|
||||
|
||||
queryset = MicrosoftEntraProviderGroup.objects.all().select_related("group")
|
||||
|
@ -1,14 +1,15 @@
|
||||
"""MicrosoftEntraProviderUser API Views"""
|
||||
|
||||
from rest_framework.viewsets import ModelViewSet
|
||||
from rest_framework import mixins
|
||||
from rest_framework.serializers import ModelSerializer
|
||||
from rest_framework.viewsets import GenericViewSet
|
||||
|
||||
from authentik.core.api.groups import GroupMemberSerializer
|
||||
from authentik.core.api.sources import SourceSerializer
|
||||
from authentik.core.api.used_by import UsedByMixin
|
||||
from authentik.enterprise.providers.microsoft_entra.models import MicrosoftEntraProviderUser
|
||||
|
||||
|
||||
class MicrosoftEntraProviderUserSerializer(SourceSerializer):
|
||||
class MicrosoftEntraProviderUserSerializer(ModelSerializer):
|
||||
"""MicrosoftEntraProviderUser Serializer"""
|
||||
|
||||
user_obj = GroupMemberSerializer(source="user", read_only=True)
|
||||
@ -20,10 +21,20 @@ class MicrosoftEntraProviderUserSerializer(SourceSerializer):
|
||||
"id",
|
||||
"user",
|
||||
"user_obj",
|
||||
"provider",
|
||||
"attributes",
|
||||
]
|
||||
extra_kwargs = {"attributes": {"read_only": True}}
|
||||
|
||||
|
||||
class MicrosoftEntraProviderUserViewSet(UsedByMixin, ModelViewSet):
|
||||
class MicrosoftEntraProviderUserViewSet(
|
||||
mixins.CreateModelMixin,
|
||||
mixins.RetrieveModelMixin,
|
||||
mixins.DestroyModelMixin,
|
||||
UsedByMixin,
|
||||
mixins.ListModelMixin,
|
||||
GenericViewSet,
|
||||
):
|
||||
"""MicrosoftEntraProviderUser Viewset"""
|
||||
|
||||
queryset = MicrosoftEntraProviderUser.objects.all().select_related("user")
|
||||
|
@ -1,5 +1,6 @@
|
||||
from asyncio import run
|
||||
from collections.abc import Coroutine
|
||||
from dataclasses import asdict
|
||||
from typing import Any
|
||||
|
||||
from azure.core.exceptions import (
|
||||
@ -15,6 +16,7 @@ from kiota_authentication_azure.azure_identity_authentication_provider import (
|
||||
AzureIdentityAuthenticationProvider,
|
||||
)
|
||||
from kiota_http.kiota_client_factory import KiotaClientFactory
|
||||
from msgraph.generated.models.entity import Entity
|
||||
from msgraph.generated.models.o_data_errors.o_data_error import ODataError
|
||||
from msgraph.graph_request_adapter import GraphRequestAdapter, options
|
||||
from msgraph.graph_service_client import GraphServiceClient
|
||||
@ -98,3 +100,10 @@ class MicrosoftEntraSyncClient[TModel: Model, TConnection: Model, TSchema: dict]
|
||||
for email in emails:
|
||||
if not any(email.endswith(f"@{domain_name}") for domain_name in self.domains):
|
||||
raise BadRequestSyncException(f"Invalid email domain: {email}")
|
||||
|
||||
def entity_as_dict(self, entity: Entity) -> dict:
|
||||
"""Create a dictionary of a model instance, making sure to remove (known) things
|
||||
we can't JSON serialize"""
|
||||
raw_data = asdict(entity)
|
||||
raw_data.pop("backing_store", None)
|
||||
return raw_data
|
||||
|
@ -36,12 +36,12 @@ class MicrosoftEntraGroupClient(
|
||||
self.mapper = PropertyMappingManager(
|
||||
self.provider.property_mappings_group.all().order_by("name").select_subclasses(),
|
||||
MicrosoftEntraProviderMapping,
|
||||
["group", "provider", "creating"],
|
||||
["group", "provider", "connection"],
|
||||
)
|
||||
|
||||
def to_schema(self, obj: Group, creating: bool) -> MSGroup:
|
||||
def to_schema(self, obj: Group, connection: MicrosoftEntraProviderGroup) -> MSGroup:
|
||||
"""Convert authentik group"""
|
||||
raw_microsoft_group = super().to_schema(obj, creating)
|
||||
raw_microsoft_group = super().to_schema(obj, connection)
|
||||
try:
|
||||
return MSGroup(**raw_microsoft_group)
|
||||
except TypeError as exc:
|
||||
@ -62,7 +62,7 @@ class MicrosoftEntraGroupClient(
|
||||
|
||||
def create(self, group: Group):
|
||||
"""Create group from scratch and create a connection object"""
|
||||
microsoft_group = self.to_schema(group, True)
|
||||
microsoft_group = self.to_schema(group, None)
|
||||
with transaction.atomic():
|
||||
try:
|
||||
response = self._request(self.client.groups.post(microsoft_group))
|
||||
@ -79,22 +79,29 @@ class MicrosoftEntraGroupClient(
|
||||
)
|
||||
)
|
||||
group_data = self._request(self.client.groups.get(request_configuration))
|
||||
if group_data.odata_count < 1:
|
||||
if group_data.odata_count < 1 or len(group_data.value) < 1:
|
||||
self.logger.warning(
|
||||
"Group which could not be created also does not exist", group=group
|
||||
)
|
||||
return
|
||||
ms_group = group_data.value[0]
|
||||
return MicrosoftEntraProviderGroup.objects.create(
|
||||
provider=self.provider, group=group, microsoft_id=group_data.value[0].id
|
||||
provider=self.provider,
|
||||
group=group,
|
||||
microsoft_id=ms_group.id,
|
||||
attributes=self.entity_as_dict(ms_group),
|
||||
)
|
||||
else:
|
||||
return MicrosoftEntraProviderGroup.objects.create(
|
||||
provider=self.provider, group=group, microsoft_id=response.id
|
||||
provider=self.provider,
|
||||
group=group,
|
||||
microsoft_id=response.id,
|
||||
attributes=self.entity_as_dict(response),
|
||||
)
|
||||
|
||||
def update(self, group: Group, connection: MicrosoftEntraProviderGroup):
|
||||
"""Update existing group"""
|
||||
microsoft_group = self.to_schema(group, False)
|
||||
microsoft_group = self.to_schema(group, connection)
|
||||
microsoft_group.id = connection.microsoft_id
|
||||
try:
|
||||
return self._request(
|
||||
@ -213,4 +220,5 @@ class MicrosoftEntraGroupClient(
|
||||
provider=self.provider,
|
||||
group=matching_authentik_group,
|
||||
microsoft_id=group.id,
|
||||
attributes=self.entity_as_dict(group),
|
||||
)
|
||||
|
@ -31,12 +31,12 @@ class MicrosoftEntraUserClient(MicrosoftEntraSyncClient[User, MicrosoftEntraProv
|
||||
self.mapper = PropertyMappingManager(
|
||||
self.provider.property_mappings.all().order_by("name").select_subclasses(),
|
||||
MicrosoftEntraProviderMapping,
|
||||
["provider", "creating"],
|
||||
["provider", "connection"],
|
||||
)
|
||||
|
||||
def to_schema(self, obj: User, creating: bool) -> MSUser:
|
||||
def to_schema(self, obj: User, connection: MicrosoftEntraProviderUser) -> MSUser:
|
||||
"""Convert authentik user"""
|
||||
raw_microsoft_user = super().to_schema(obj, creating)
|
||||
raw_microsoft_user = super().to_schema(obj, connection)
|
||||
try:
|
||||
return MSUser(**delete_none_values(raw_microsoft_user))
|
||||
except TypeError as exc:
|
||||
@ -67,7 +67,7 @@ class MicrosoftEntraUserClient(MicrosoftEntraSyncClient[User, MicrosoftEntraProv
|
||||
|
||||
def create(self, user: User):
|
||||
"""Create user from scratch and create a connection object"""
|
||||
microsoft_user = self.to_schema(user, True)
|
||||
microsoft_user = self.to_schema(user, None)
|
||||
self.check_email_valid(microsoft_user.user_principal_name)
|
||||
with transaction.atomic():
|
||||
try:
|
||||
@ -83,24 +83,32 @@ class MicrosoftEntraUserClient(MicrosoftEntraSyncClient[User, MicrosoftEntraProv
|
||||
)
|
||||
)
|
||||
user_data = self._request(self.client.users.get(request_configuration))
|
||||
if user_data.odata_count < 1:
|
||||
if user_data.odata_count < 1 or len(user_data.value) < 1:
|
||||
self.logger.warning(
|
||||
"User which could not be created also does not exist", user=user
|
||||
)
|
||||
return
|
||||
ms_user = user_data.value[0]
|
||||
return MicrosoftEntraProviderUser.objects.create(
|
||||
provider=self.provider, user=user, microsoft_id=user_data.value[0].id
|
||||
provider=self.provider,
|
||||
user=user,
|
||||
microsoft_id=ms_user.id,
|
||||
attributes=self.entity_as_dict(ms_user),
|
||||
)
|
||||
except TransientSyncException as exc:
|
||||
raise exc
|
||||
else:
|
||||
print(self.entity_as_dict(response))
|
||||
return MicrosoftEntraProviderUser.objects.create(
|
||||
provider=self.provider, user=user, microsoft_id=response.id
|
||||
provider=self.provider,
|
||||
user=user,
|
||||
microsoft_id=response.id,
|
||||
attributes=self.entity_as_dict(response),
|
||||
)
|
||||
|
||||
def update(self, user: User, connection: MicrosoftEntraProviderUser):
|
||||
"""Update existing user"""
|
||||
microsoft_user = self.to_schema(user, False)
|
||||
microsoft_user = self.to_schema(user, connection)
|
||||
self.check_email_valid(microsoft_user.user_principal_name)
|
||||
self._request(self.client.users.by_user_id(connection.microsoft_id).patch(microsoft_user))
|
||||
|
||||
@ -125,4 +133,5 @@ class MicrosoftEntraUserClient(MicrosoftEntraSyncClient[User, MicrosoftEntraProv
|
||||
provider=self.provider,
|
||||
user=matching_authentik_user,
|
||||
microsoft_id=user.id,
|
||||
attributes=self.entity_as_dict(user),
|
||||
)
|
||||
|
@ -0,0 +1,23 @@
|
||||
# Generated by Django 5.0.6 on 2024-05-23 20:48
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("authentik_providers_microsoft_entra", "0001_initial"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="microsoftentraprovidergroup",
|
||||
name="attributes",
|
||||
field=models.JSONField(default=dict),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="microsoftentraprovideruser",
|
||||
name="attributes",
|
||||
field=models.JSONField(default=dict),
|
||||
),
|
||||
]
|
@ -142,6 +142,7 @@ class MicrosoftEntraProviderUser(SerializerModel):
|
||||
microsoft_id = models.TextField()
|
||||
user = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||
provider = models.ForeignKey(MicrosoftEntraProvider, on_delete=models.CASCADE)
|
||||
attributes = models.JSONField(default=dict)
|
||||
|
||||
@property
|
||||
def serializer(self) -> type[Serializer]:
|
||||
@ -167,6 +168,7 @@ class MicrosoftEntraProviderGroup(SerializerModel):
|
||||
microsoft_id = models.TextField()
|
||||
group = models.ForeignKey(Group, on_delete=models.CASCADE)
|
||||
provider = models.ForeignKey(MicrosoftEntraProvider, on_delete=models.CASCADE)
|
||||
attributes = models.JSONField(default=dict)
|
||||
|
||||
@property
|
||||
def serializer(self) -> type[Serializer]:
|
||||
|
@ -3,3 +3,6 @@
|
||||
PAGE_SIZE = 100
|
||||
PAGE_TIMEOUT = 60 * 60 * 0.5 # Half an hour
|
||||
HTTP_CONFLICT = 409
|
||||
HTTP_NO_CONTENT = 204
|
||||
HTTP_SERVICE_UNAVAILABLE = 503
|
||||
HTTP_TOO_MANY_REQUESTS = 429
|
||||
|
@ -79,14 +79,14 @@ class BaseOutgoingSyncClient[
|
||||
"""Delete object from destination"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def to_schema(self, obj: TModel, creating: bool, **defaults) -> TSchema:
|
||||
def to_schema(self, obj: TModel, connection: TConnection | None, **defaults) -> TSchema:
|
||||
"""Convert object to destination schema"""
|
||||
raw_final_object = {}
|
||||
try:
|
||||
eval_kwargs = {
|
||||
"request": None,
|
||||
"provider": self.provider,
|
||||
"creating": creating,
|
||||
"connection": connection,
|
||||
obj._meta.model_name: obj,
|
||||
}
|
||||
eval_kwargs.setdefault("user", None)
|
||||
|
@ -124,7 +124,6 @@ class KubernetesObjectReconciler(Generic[T]):
|
||||
self.update(current, reference)
|
||||
self.logger.debug("Updating")
|
||||
except (OpenApiException, HTTPError) as exc:
|
||||
|
||||
if isinstance(exc, ApiException) and exc.status == 422: # noqa: PLR2004
|
||||
self.logger.debug("Failed to update current, triggering re-create")
|
||||
self._recreate(current=current, reference=reference)
|
||||
|
@ -6,9 +6,18 @@ from django.http import HttpResponseBadRequest, HttpResponseNotFound
|
||||
from pydantic import ValidationError
|
||||
from requests import RequestException, Session
|
||||
|
||||
from authentik.lib.sync.outgoing import HTTP_CONFLICT
|
||||
from authentik.lib.sync.outgoing import (
|
||||
HTTP_CONFLICT,
|
||||
HTTP_NO_CONTENT,
|
||||
HTTP_SERVICE_UNAVAILABLE,
|
||||
HTTP_TOO_MANY_REQUESTS,
|
||||
)
|
||||
from authentik.lib.sync.outgoing.base import BaseOutgoingSyncClient
|
||||
from authentik.lib.sync.outgoing.exceptions import NotFoundSyncException, ObjectExistsSyncException
|
||||
from authentik.lib.sync.outgoing.exceptions import (
|
||||
NotFoundSyncException,
|
||||
ObjectExistsSyncException,
|
||||
TransientSyncException,
|
||||
)
|
||||
from authentik.lib.utils.http import get_http_session
|
||||
from authentik.providers.scim.clients.exceptions import SCIMRequestException
|
||||
from authentik.providers.scim.clients.schema import ServiceProviderConfiguration
|
||||
@ -61,13 +70,15 @@ class SCIMClient[TModel: "Model", TConnection: "Model", TSchema: "BaseModel"](
|
||||
if response.status_code >= HttpResponseBadRequest.status_code:
|
||||
if response.status_code == HttpResponseNotFound.status_code:
|
||||
raise NotFoundSyncException(response)
|
||||
if response.status_code in [HTTP_TOO_MANY_REQUESTS, HTTP_SERVICE_UNAVAILABLE]:
|
||||
raise TransientSyncException()
|
||||
if response.status_code == HTTP_CONFLICT:
|
||||
raise ObjectExistsSyncException(response)
|
||||
self.logger.warning(
|
||||
"Failed to send SCIM request", path=path, method=method, response=response.text
|
||||
)
|
||||
raise SCIMRequestException(response)
|
||||
if response.status_code == 204: # noqa: PLR2004
|
||||
if response.status_code == HTTP_NO_CONTENT:
|
||||
return {}
|
||||
return response.json()
|
||||
|
||||
|
@ -34,14 +34,14 @@ class SCIMGroupClient(SCIMClient[Group, SCIMGroup, SCIMGroupSchema]):
|
||||
self.mapper = PropertyMappingManager(
|
||||
self.provider.property_mappings_group.all().order_by("name").select_subclasses(),
|
||||
SCIMMapping,
|
||||
["group", "provider", "creating"],
|
||||
["group", "provider", "connection"],
|
||||
)
|
||||
|
||||
def to_schema(self, obj: Group, creating: bool) -> SCIMGroupSchema:
|
||||
def to_schema(self, obj: Group, connection: SCIMGroup) -> SCIMGroupSchema:
|
||||
"""Convert authentik user into SCIM"""
|
||||
raw_scim_group = super().to_schema(
|
||||
obj,
|
||||
creating,
|
||||
connection,
|
||||
schemas=(SCIM_GROUP_SCHEMA,),
|
||||
)
|
||||
try:
|
||||
@ -76,7 +76,7 @@ class SCIMGroupClient(SCIMClient[Group, SCIMGroup, SCIMGroupSchema]):
|
||||
|
||||
def create(self, group: Group):
|
||||
"""Create group from scratch and create a connection object"""
|
||||
scim_group = self.to_schema(group, True)
|
||||
scim_group = self.to_schema(group, None)
|
||||
response = self._request(
|
||||
"POST",
|
||||
"/Groups",
|
||||
@ -92,7 +92,7 @@ class SCIMGroupClient(SCIMClient[Group, SCIMGroup, SCIMGroupSchema]):
|
||||
|
||||
def update(self, group: Group, connection: SCIMGroup):
|
||||
"""Update existing group"""
|
||||
scim_group = self.to_schema(group, False)
|
||||
scim_group = self.to_schema(group, connection)
|
||||
scim_group.id = connection.scim_id
|
||||
try:
|
||||
return self._request(
|
||||
|
@ -24,14 +24,14 @@ class SCIMUserClient(SCIMClient[User, SCIMUser, SCIMUserSchema]):
|
||||
self.mapper = PropertyMappingManager(
|
||||
self.provider.property_mappings.all().order_by("name").select_subclasses(),
|
||||
SCIMMapping,
|
||||
["provider", "creating"],
|
||||
["provider", "connection"],
|
||||
)
|
||||
|
||||
def to_schema(self, obj: User, creating: bool) -> SCIMUserSchema:
|
||||
def to_schema(self, obj: User, connection: SCIMUser) -> SCIMUserSchema:
|
||||
"""Convert authentik user into SCIM"""
|
||||
raw_scim_user = super().to_schema(
|
||||
obj,
|
||||
creating,
|
||||
connection,
|
||||
schemas=(SCIM_USER_SCHEMA,),
|
||||
)
|
||||
try:
|
||||
@ -54,7 +54,7 @@ class SCIMUserClient(SCIMClient[User, SCIMUser, SCIMUserSchema]):
|
||||
|
||||
def create(self, user: User):
|
||||
"""Create user from scratch and create a connection object"""
|
||||
scim_user = self.to_schema(user, True)
|
||||
scim_user = self.to_schema(user, None)
|
||||
response = self._request(
|
||||
"POST",
|
||||
"/Users",
|
||||
@ -70,7 +70,7 @@ class SCIMUserClient(SCIMClient[User, SCIMUser, SCIMUserSchema]):
|
||||
|
||||
def update(self, user: User, connection: SCIMUser):
|
||||
"""Update existing user"""
|
||||
scim_user = self.to_schema(user, False)
|
||||
scim_user = self.to_schema(user, connection)
|
||||
scim_user.id = connection.scim_id
|
||||
self._request(
|
||||
"PUT",
|
||||
|
@ -19,10 +19,16 @@ entries:
|
||||
"mail_nickname": request.user.username,
|
||||
"user_principal_name": request.user.email,
|
||||
}
|
||||
if creating:
|
||||
if connection:
|
||||
# If there is a connection already made (discover or update), we can use
|
||||
# that connection's immutable_id...
|
||||
user["on_premises_immutable_id"] = connection.attributes.get("on_premises_immutable_id")
|
||||
else:
|
||||
user["password_profile"] = PasswordProfile(
|
||||
password=request.user.password
|
||||
)
|
||||
# ...otherwise we set an immutable ID based on the user's UID
|
||||
user["on_premises_immutable_id"] = request.user.uid,
|
||||
return user
|
||||
- identifiers:
|
||||
managed: goauthentik.io/providers/microsoft_entra/group
|
||||
|
378
schema.yml
378
schema.yml
@ -16369,85 +16369,6 @@ paths:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GenericError'
|
||||
description: ''
|
||||
put:
|
||||
operationId: providers_google_workspace_groups_update
|
||||
description: GoogleWorkspaceProviderGroup Viewset
|
||||
parameters:
|
||||
- in: path
|
||||
name: id
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
description: A UUID string identifying this Google Workspace Provider Group.
|
||||
required: true
|
||||
tags:
|
||||
- providers
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GoogleWorkspaceProviderGroupRequest'
|
||||
required: true
|
||||
security:
|
||||
- authentik: []
|
||||
responses:
|
||||
'200':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GoogleWorkspaceProviderGroup'
|
||||
description: ''
|
||||
'400':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ValidationError'
|
||||
description: ''
|
||||
'403':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GenericError'
|
||||
description: ''
|
||||
patch:
|
||||
operationId: providers_google_workspace_groups_partial_update
|
||||
description: GoogleWorkspaceProviderGroup Viewset
|
||||
parameters:
|
||||
- in: path
|
||||
name: id
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
description: A UUID string identifying this Google Workspace Provider Group.
|
||||
required: true
|
||||
tags:
|
||||
- providers
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/PatchedGoogleWorkspaceProviderGroupRequest'
|
||||
security:
|
||||
- authentik: []
|
||||
responses:
|
||||
'200':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GoogleWorkspaceProviderGroup'
|
||||
description: ''
|
||||
'400':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ValidationError'
|
||||
description: ''
|
||||
'403':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GenericError'
|
||||
description: ''
|
||||
delete:
|
||||
operationId: providers_google_workspace_groups_destroy
|
||||
description: GoogleWorkspaceProviderGroup Viewset
|
||||
@ -16646,85 +16567,6 @@ paths:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GenericError'
|
||||
description: ''
|
||||
put:
|
||||
operationId: providers_google_workspace_users_update
|
||||
description: GoogleWorkspaceProviderUser Viewset
|
||||
parameters:
|
||||
- in: path
|
||||
name: id
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
description: A UUID string identifying this Google Workspace Provider User.
|
||||
required: true
|
||||
tags:
|
||||
- providers
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GoogleWorkspaceProviderUserRequest'
|
||||
required: true
|
||||
security:
|
||||
- authentik: []
|
||||
responses:
|
||||
'200':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GoogleWorkspaceProviderUser'
|
||||
description: ''
|
||||
'400':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ValidationError'
|
||||
description: ''
|
||||
'403':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GenericError'
|
||||
description: ''
|
||||
patch:
|
||||
operationId: providers_google_workspace_users_partial_update
|
||||
description: GoogleWorkspaceProviderUser Viewset
|
||||
parameters:
|
||||
- in: path
|
||||
name: id
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
description: A UUID string identifying this Google Workspace Provider User.
|
||||
required: true
|
||||
tags:
|
||||
- providers
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/PatchedGoogleWorkspaceProviderUserRequest'
|
||||
security:
|
||||
- authentik: []
|
||||
responses:
|
||||
'200':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GoogleWorkspaceProviderUser'
|
||||
description: ''
|
||||
'400':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ValidationError'
|
||||
description: ''
|
||||
'403':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GenericError'
|
||||
description: ''
|
||||
delete:
|
||||
operationId: providers_google_workspace_users_destroy
|
||||
description: GoogleWorkspaceProviderUser Viewset
|
||||
@ -17539,85 +17381,6 @@ paths:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GenericError'
|
||||
description: ''
|
||||
put:
|
||||
operationId: providers_microsoft_entra_groups_update
|
||||
description: MicrosoftEntraProviderGroup Viewset
|
||||
parameters:
|
||||
- in: path
|
||||
name: id
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
description: A UUID string identifying this Microsoft Entra Provider Group.
|
||||
required: true
|
||||
tags:
|
||||
- providers
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/MicrosoftEntraProviderGroupRequest'
|
||||
required: true
|
||||
security:
|
||||
- authentik: []
|
||||
responses:
|
||||
'200':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/MicrosoftEntraProviderGroup'
|
||||
description: ''
|
||||
'400':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ValidationError'
|
||||
description: ''
|
||||
'403':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GenericError'
|
||||
description: ''
|
||||
patch:
|
||||
operationId: providers_microsoft_entra_groups_partial_update
|
||||
description: MicrosoftEntraProviderGroup Viewset
|
||||
parameters:
|
||||
- in: path
|
||||
name: id
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
description: A UUID string identifying this Microsoft Entra Provider Group.
|
||||
required: true
|
||||
tags:
|
||||
- providers
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/PatchedMicrosoftEntraProviderGroupRequest'
|
||||
security:
|
||||
- authentik: []
|
||||
responses:
|
||||
'200':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/MicrosoftEntraProviderGroup'
|
||||
description: ''
|
||||
'400':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ValidationError'
|
||||
description: ''
|
||||
'403':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GenericError'
|
||||
description: ''
|
||||
delete:
|
||||
operationId: providers_microsoft_entra_groups_destroy
|
||||
description: MicrosoftEntraProviderGroup Viewset
|
||||
@ -17816,85 +17579,6 @@ paths:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GenericError'
|
||||
description: ''
|
||||
put:
|
||||
operationId: providers_microsoft_entra_users_update
|
||||
description: MicrosoftEntraProviderUser Viewset
|
||||
parameters:
|
||||
- in: path
|
||||
name: id
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
description: A UUID string identifying this Microsoft Entra Provider User.
|
||||
required: true
|
||||
tags:
|
||||
- providers
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/MicrosoftEntraProviderUserRequest'
|
||||
required: true
|
||||
security:
|
||||
- authentik: []
|
||||
responses:
|
||||
'200':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/MicrosoftEntraProviderUser'
|
||||
description: ''
|
||||
'400':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ValidationError'
|
||||
description: ''
|
||||
'403':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GenericError'
|
||||
description: ''
|
||||
patch:
|
||||
operationId: providers_microsoft_entra_users_partial_update
|
||||
description: MicrosoftEntraProviderUser Viewset
|
||||
parameters:
|
||||
- in: path
|
||||
name: id
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
description: A UUID string identifying this Microsoft Entra Provider User.
|
||||
required: true
|
||||
tags:
|
||||
- providers
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/PatchedMicrosoftEntraProviderUserRequest'
|
||||
security:
|
||||
- authentik: []
|
||||
responses:
|
||||
'200':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/MicrosoftEntraProviderUser'
|
||||
description: ''
|
||||
'400':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ValidationError'
|
||||
description: ''
|
||||
'403':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GenericError'
|
||||
description: ''
|
||||
delete:
|
||||
operationId: providers_microsoft_entra_users_destroy
|
||||
description: MicrosoftEntraProviderUser Viewset
|
||||
@ -36634,10 +36318,16 @@ components:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/UserGroup'
|
||||
readOnly: true
|
||||
provider:
|
||||
type: integer
|
||||
attributes:
|
||||
readOnly: true
|
||||
required:
|
||||
- attributes
|
||||
- group
|
||||
- group_obj
|
||||
- id
|
||||
- provider
|
||||
GoogleWorkspaceProviderGroupRequest:
|
||||
type: object
|
||||
description: GoogleWorkspaceProviderGroup Serializer
|
||||
@ -36645,8 +36335,11 @@ components:
|
||||
group:
|
||||
type: string
|
||||
format: uuid
|
||||
provider:
|
||||
type: integer
|
||||
required:
|
||||
- group
|
||||
- provider
|
||||
GoogleWorkspaceProviderMapping:
|
||||
type: object
|
||||
description: GoogleWorkspaceProviderMapping Serializer
|
||||
@ -36773,8 +36466,14 @@ components:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/GroupMember'
|
||||
readOnly: true
|
||||
provider:
|
||||
type: integer
|
||||
attributes:
|
||||
readOnly: true
|
||||
required:
|
||||
- attributes
|
||||
- id
|
||||
- provider
|
||||
- user
|
||||
- user_obj
|
||||
GoogleWorkspaceProviderUserRequest:
|
||||
@ -36783,7 +36482,10 @@ components:
|
||||
properties:
|
||||
user:
|
||||
type: integer
|
||||
provider:
|
||||
type: integer
|
||||
required:
|
||||
- provider
|
||||
- user
|
||||
Group:
|
||||
type: object
|
||||
@ -38284,10 +37986,16 @@ components:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/UserGroup'
|
||||
readOnly: true
|
||||
provider:
|
||||
type: integer
|
||||
attributes:
|
||||
readOnly: true
|
||||
required:
|
||||
- attributes
|
||||
- group
|
||||
- group_obj
|
||||
- id
|
||||
- provider
|
||||
MicrosoftEntraProviderGroupRequest:
|
||||
type: object
|
||||
description: MicrosoftEntraProviderGroup Serializer
|
||||
@ -38295,8 +38003,11 @@ components:
|
||||
group:
|
||||
type: string
|
||||
format: uuid
|
||||
provider:
|
||||
type: integer
|
||||
required:
|
||||
- group
|
||||
- provider
|
||||
MicrosoftEntraProviderMapping:
|
||||
type: object
|
||||
description: MicrosoftEntraProviderMapping Serializer
|
||||
@ -38420,8 +38131,14 @@ components:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/GroupMember'
|
||||
readOnly: true
|
||||
provider:
|
||||
type: integer
|
||||
attributes:
|
||||
readOnly: true
|
||||
required:
|
||||
- attributes
|
||||
- id
|
||||
- provider
|
||||
- user
|
||||
- user_obj
|
||||
MicrosoftEntraProviderUserRequest:
|
||||
@ -38430,7 +38147,10 @@ components:
|
||||
properties:
|
||||
user:
|
||||
type: integer
|
||||
provider:
|
||||
type: integer
|
||||
required:
|
||||
- provider
|
||||
- user
|
||||
ModelEnum:
|
||||
enum:
|
||||
@ -41826,13 +41546,6 @@ components:
|
||||
to a challenge. RETRY returns the error message and a similar challenge
|
||||
to the executor. RESTART restarts the flow from the beginning, and RESTART_WITH_CONTEXT
|
||||
restarts the flow while keeping the current context.
|
||||
PatchedGoogleWorkspaceProviderGroupRequest:
|
||||
type: object
|
||||
description: GoogleWorkspaceProviderGroup Serializer
|
||||
properties:
|
||||
group:
|
||||
type: string
|
||||
format: uuid
|
||||
PatchedGoogleWorkspaceProviderMappingRequest:
|
||||
type: object
|
||||
description: GoogleWorkspaceProviderMapping Serializer
|
||||
@ -41892,12 +41605,6 @@ components:
|
||||
default_group_email_domain:
|
||||
type: string
|
||||
minLength: 1
|
||||
PatchedGoogleWorkspaceProviderUserRequest:
|
||||
type: object
|
||||
description: GoogleWorkspaceProviderUser Serializer
|
||||
properties:
|
||||
user:
|
||||
type: integer
|
||||
PatchedGroupRequest:
|
||||
type: object
|
||||
description: Group Serializer
|
||||
@ -42253,13 +41960,6 @@ components:
|
||||
key:
|
||||
type: string
|
||||
minLength: 1
|
||||
PatchedMicrosoftEntraProviderGroupRequest:
|
||||
type: object
|
||||
description: MicrosoftEntraProviderGroup Serializer
|
||||
properties:
|
||||
group:
|
||||
type: string
|
||||
format: uuid
|
||||
PatchedMicrosoftEntraProviderMappingRequest:
|
||||
type: object
|
||||
description: MicrosoftEntraProviderMapping Serializer
|
||||
@ -42316,12 +42016,6 @@ components:
|
||||
$ref: '#/components/schemas/OutgoingSyncDeleteAction'
|
||||
group_delete_action:
|
||||
$ref: '#/components/schemas/OutgoingSyncDeleteAction'
|
||||
PatchedMicrosoftEntraProviderUserRequest:
|
||||
type: object
|
||||
description: MicrosoftEntraProviderUser Serializer
|
||||
properties:
|
||||
user:
|
||||
type: integer
|
||||
PatchedNotificationRequest:
|
||||
type: object
|
||||
description: Notification Serializer
|
||||
|
@ -13,6 +13,8 @@ export class GoogleWorkspaceProviderGroupList extends Table<GoogleWorkspaceProvi
|
||||
@property({ type: Number })
|
||||
providerId?: number;
|
||||
|
||||
expandable = true;
|
||||
|
||||
searchEnabled(): boolean {
|
||||
return true;
|
||||
}
|
||||
@ -39,4 +41,12 @@ export class GoogleWorkspaceProviderGroupList extends Table<GoogleWorkspaceProvi
|
||||
html`${item.id}`,
|
||||
];
|
||||
}
|
||||
|
||||
renderExpanded(item: GoogleWorkspaceProviderGroup): TemplateResult {
|
||||
return html`<td role="cell" colspan="4">
|
||||
<div class="pf-c-table__expandable-row-content">
|
||||
<pre>${JSON.stringify(item.attributes, null, 4)}</pre>
|
||||
</div>
|
||||
</td>`;
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,8 @@ export class GoogleWorkspaceProviderUserList extends Table<GoogleWorkspaceProvid
|
||||
return true;
|
||||
}
|
||||
|
||||
expandable = true;
|
||||
|
||||
async apiEndpoint(page: number): Promise<PaginatedResponse<GoogleWorkspaceProviderUser>> {
|
||||
return new ProvidersApi(DEFAULT_CONFIG).providersGoogleWorkspaceUsersList({
|
||||
page: page,
|
||||
@ -40,4 +42,12 @@ export class GoogleWorkspaceProviderUserList extends Table<GoogleWorkspaceProvid
|
||||
html`${item.id}`,
|
||||
];
|
||||
}
|
||||
|
||||
renderExpanded(item: GoogleWorkspaceProviderUser): TemplateResult {
|
||||
return html`<td role="cell" colspan="4">
|
||||
<div class="pf-c-table__expandable-row-content">
|
||||
<pre>${JSON.stringify(item.attributes, null, 4)}</pre>
|
||||
</div>
|
||||
</td>`;
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,8 @@ export class MicrosoftEntraProviderGroupList extends Table<MicrosoftEntraProvide
|
||||
@property({ type: Number })
|
||||
providerId?: number;
|
||||
|
||||
expandable = true;
|
||||
|
||||
searchEnabled(): boolean {
|
||||
return true;
|
||||
}
|
||||
@ -39,4 +41,12 @@ export class MicrosoftEntraProviderGroupList extends Table<MicrosoftEntraProvide
|
||||
html`${item.id}`,
|
||||
];
|
||||
}
|
||||
|
||||
renderExpanded(item: MicrosoftEntraProviderGroup): TemplateResult {
|
||||
return html`<td role="cell" colspan="4">
|
||||
<div class="pf-c-table__expandable-row-content">
|
||||
<pre>${JSON.stringify(item.attributes, null, 4)}</pre>
|
||||
</div>
|
||||
</td>`;
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,8 @@ export class MicrosoftEntraProviderUserList extends Table<MicrosoftEntraProvider
|
||||
@property({ type: Number })
|
||||
providerId?: number;
|
||||
|
||||
expandable = true;
|
||||
|
||||
searchEnabled(): boolean {
|
||||
return true;
|
||||
}
|
||||
@ -40,4 +42,12 @@ export class MicrosoftEntraProviderUserList extends Table<MicrosoftEntraProvider
|
||||
html`${item.id}`,
|
||||
];
|
||||
}
|
||||
|
||||
renderExpanded(item: MicrosoftEntraProviderUser): TemplateResult {
|
||||
return html`<td role="cell" colspan="4">
|
||||
<div class="pf-c-table__expandable-row-content">
|
||||
<pre>${JSON.stringify(item.attributes, null, 4)}</pre>
|
||||
</div>
|
||||
</td>`;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user