providers/sync: improve v3 (#9966)
* make external id field externally visible Signed-off-by: Jens Langhammer <jens@goauthentik.io> * catch up scim provider Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add missing views to scim provider Signed-off-by: Jens Langhammer <jens@goauthentik.io> * make neither user nor group required for mapping testing Signed-off-by: Jens Langhammer <jens@goauthentik.io> * improve SkipObject handling Signed-off-by: Jens Langhammer <jens@goauthentik.io> * allow deletion of connection objects Signed-off-by: Jens Langhammer <jens@goauthentik.io> * make entra logs less noisy Signed-off-by: Jens Langhammer <jens@goauthentik.io> * make event_matcher less noisy Signed-off-by: Jens Langhammer <jens@goauthentik.io> --------- Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
		| @ -58,7 +58,7 @@ from authentik.outposts.models import OutpostServiceConnection | ||||
| from authentik.policies.models import Policy, PolicyBindingModel | ||||
| from authentik.policies.reputation.models import Reputation | ||||
| from authentik.providers.oauth2.models import AccessToken, AuthorizationCode, RefreshToken | ||||
| from authentik.providers.scim.models import SCIMGroup, SCIMUser | ||||
| from authentik.providers.scim.models import SCIMProviderGroup, SCIMProviderUser | ||||
| from authentik.sources.scim.models import SCIMSourceGroup, SCIMSourceUser | ||||
| from authentik.stages.authenticator_webauthn.models import WebAuthnDeviceType | ||||
| from authentik.tenants.models import Tenant | ||||
| @ -97,8 +97,8 @@ def excluded_models() -> list[type[Model]]: | ||||
|         # FIXME: these shouldn't need to be explicitly listed, but rather based off of a mixin | ||||
|         FlowToken, | ||||
|         LicenseUsage, | ||||
|         SCIMGroup, | ||||
|         SCIMUser, | ||||
|         SCIMProviderGroup, | ||||
|         SCIMProviderUser, | ||||
|         Tenant, | ||||
|         SystemTask, | ||||
|         ConnectionToken, | ||||
|  | ||||
| @ -80,8 +80,10 @@ class PropertyMappingViewSet( | ||||
|     class PropertyMappingTestSerializer(PolicyTestSerializer): | ||||
|         """Test property mapping execution for a user/group with context""" | ||||
|  | ||||
|         user = PrimaryKeyRelatedField(queryset=User.objects.all(), required=False) | ||||
|         group = PrimaryKeyRelatedField(queryset=Group.objects.all(), required=False) | ||||
|         user = PrimaryKeyRelatedField(queryset=User.objects.all(), required=False, allow_null=True) | ||||
|         group = PrimaryKeyRelatedField( | ||||
|             queryset=Group.objects.all(), required=False, allow_null=True | ||||
|         ) | ||||
|  | ||||
|     queryset = PropertyMapping.objects.select_subclasses() | ||||
|     serializer_class = PropertyMappingSerializer | ||||
|  | ||||
| @ -19,6 +19,7 @@ class GoogleWorkspaceProviderGroupSerializer(ModelSerializer): | ||||
|         model = GoogleWorkspaceProviderGroup | ||||
|         fields = [ | ||||
|             "id", | ||||
|             "google_id", | ||||
|             "group", | ||||
|             "group_obj", | ||||
|             "provider", | ||||
|  | ||||
| @ -19,6 +19,7 @@ class GoogleWorkspaceProviderUserSerializer(ModelSerializer): | ||||
|         model = GoogleWorkspaceProviderUser | ||||
|         fields = [ | ||||
|             "id", | ||||
|             "google_id", | ||||
|             "user", | ||||
|             "user_obj", | ||||
|             "provider", | ||||
|  | ||||
| @ -19,6 +19,7 @@ class MicrosoftEntraProviderGroupSerializer(ModelSerializer): | ||||
|         model = MicrosoftEntraProviderGroup | ||||
|         fields = [ | ||||
|             "id", | ||||
|             "microsoft_id", | ||||
|             "group", | ||||
|             "group_obj", | ||||
|             "provider", | ||||
|  | ||||
| @ -19,6 +19,7 @@ class MicrosoftEntraProviderUserSerializer(ModelSerializer): | ||||
|         model = MicrosoftEntraProviderUser | ||||
|         fields = [ | ||||
|             "id", | ||||
|             "microsoft_id", | ||||
|             "user", | ||||
|             "user_obj", | ||||
|             "provider", | ||||
|  | ||||
| @ -102,6 +102,8 @@ def get_logger_config(): | ||||
|         "gunicorn": "INFO", | ||||
|         "requests_mock": "WARNING", | ||||
|         "hpack": "WARNING", | ||||
|         "httpx": "WARNING", | ||||
|         "azure": "WARNING", | ||||
|     } | ||||
|     for handler_name, level in handler_level_map.items(): | ||||
|         base_config["loggers"][handler_name] = { | ||||
|  | ||||
| @ -57,6 +57,8 @@ class PropertyMappingManager: | ||||
|             mapping.set_context(user, request, **kwargs) | ||||
|             try: | ||||
|                 value = mapping.evaluate(mapping.model.expression) | ||||
|             except PropertyMappingExpressionException as exc: | ||||
|                 raise exc from exc | ||||
|             except Exception as exc: | ||||
|                 raise PropertyMappingExpressionException(exc, mapping.model) from exc | ||||
|             if value is None: | ||||
|  | ||||
| @ -91,7 +91,6 @@ class BaseOutgoingSyncClient[ | ||||
|             } | ||||
|             eval_kwargs.setdefault("user", None) | ||||
|             for value in self.mapper.iter_eval(**eval_kwargs): | ||||
|                 try: | ||||
|                 always_merger.merge(raw_final_object, value) | ||||
|         except SkipObjectException as exc: | ||||
|             raise exc from exc | ||||
| @ -104,7 +103,7 @@ class BaseOutgoingSyncClient[ | ||||
|             ).save() | ||||
|             raise StopSync(exc, obj, exc.mapping) from exc | ||||
|         if not raw_final_object: | ||||
|             raise StopSync(ValueError("No user mappings configured"), obj) | ||||
|             raise StopSync(ValueError("No mappings configured"), obj) | ||||
|         for key, value in defaults.items(): | ||||
|             raw_final_object.setdefault(key, value) | ||||
|         return raw_final_object | ||||
|  | ||||
| @ -125,6 +125,7 @@ class SyncTasks: | ||||
|             try: | ||||
|                 client.write(obj) | ||||
|             except SkipObjectException: | ||||
|                 self.logger.debug("skipping object due to SkipObject", obj=obj) | ||||
|                 continue | ||||
|             except BadRequestSyncException as exc: | ||||
|                 self.logger.warning("failed to sync object", exc=exc, obj=obj) | ||||
|  | ||||
| @ -102,7 +102,7 @@ class EventMatcherPolicy(Policy): | ||||
|             result = checker(request, event) | ||||
|             if result is None: | ||||
|                 continue | ||||
|             LOGGER.info( | ||||
|             LOGGER.debug( | ||||
|                 "Event matcher check result", | ||||
|                 checker=checker.__name__, | ||||
|                 result=result, | ||||
|  | ||||
							
								
								
									
										43
									
								
								authentik/providers/scim/api/groups.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								authentik/providers/scim/api/groups.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,43 @@ | ||||
| """SCIMProviderGroup API Views""" | ||||
|  | ||||
| from rest_framework import mixins | ||||
| from rest_framework.serializers import ModelSerializer | ||||
| from rest_framework.viewsets import GenericViewSet | ||||
|  | ||||
| from authentik.core.api.used_by import UsedByMixin | ||||
| from authentik.core.api.users import UserGroupSerializer | ||||
| from authentik.providers.scim.models import SCIMProviderGroup | ||||
|  | ||||
|  | ||||
| class SCIMProviderGroupSerializer(ModelSerializer): | ||||
|     """SCIMProviderGroup Serializer""" | ||||
|  | ||||
|     group_obj = UserGroupSerializer(source="group", read_only=True) | ||||
|  | ||||
|     class Meta: | ||||
|  | ||||
|         model = SCIMProviderGroup | ||||
|         fields = [ | ||||
|             "id", | ||||
|             "scim_id", | ||||
|             "group", | ||||
|             "group_obj", | ||||
|             "provider", | ||||
|         ] | ||||
|  | ||||
|  | ||||
| class SCIMProviderGroupViewSet( | ||||
|     mixins.CreateModelMixin, | ||||
|     mixins.RetrieveModelMixin, | ||||
|     mixins.DestroyModelMixin, | ||||
|     UsedByMixin, | ||||
|     mixins.ListModelMixin, | ||||
|     GenericViewSet, | ||||
| ): | ||||
|     """SCIMProviderGroup Viewset""" | ||||
|  | ||||
|     queryset = SCIMProviderGroup.objects.all().select_related("group") | ||||
|     serializer_class = SCIMProviderGroupSerializer | ||||
|     filterset_fields = ["provider__id", "group__name", "group__group_uuid"] | ||||
|     search_fields = ["provider__name", "group__name"] | ||||
|     ordering = ["group__name"] | ||||
							
								
								
									
										43
									
								
								authentik/providers/scim/api/users.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								authentik/providers/scim/api/users.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,43 @@ | ||||
| """SCIMProviderUser API Views""" | ||||
|  | ||||
| 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.used_by import UsedByMixin | ||||
| from authentik.providers.scim.models import SCIMProviderUser | ||||
|  | ||||
|  | ||||
| class SCIMProviderUserSerializer(ModelSerializer): | ||||
|     """SCIMProviderUser Serializer""" | ||||
|  | ||||
|     user_obj = GroupMemberSerializer(source="user", read_only=True) | ||||
|  | ||||
|     class Meta: | ||||
|  | ||||
|         model = SCIMProviderUser | ||||
|         fields = [ | ||||
|             "id", | ||||
|             "scim_id", | ||||
|             "user", | ||||
|             "user_obj", | ||||
|             "provider", | ||||
|         ] | ||||
|  | ||||
|  | ||||
| class SCIMProviderUserViewSet( | ||||
|     mixins.CreateModelMixin, | ||||
|     mixins.RetrieveModelMixin, | ||||
|     mixins.DestroyModelMixin, | ||||
|     UsedByMixin, | ||||
|     mixins.ListModelMixin, | ||||
|     GenericViewSet, | ||||
| ): | ||||
|     """SCIMProviderUser Viewset""" | ||||
|  | ||||
|     queryset = SCIMProviderUser.objects.all().select_related("user") | ||||
|     serializer_class = SCIMProviderUserSerializer | ||||
|     filterset_fields = ["provider__id", "user__username", "user__id"] | ||||
|     search_fields = ["provider__name", "user__username"] | ||||
|     ordering = ["user__username"] | ||||
| @ -19,13 +19,18 @@ from authentik.providers.scim.clients.exceptions import ( | ||||
| ) | ||||
| from authentik.providers.scim.clients.schema import SCIM_GROUP_SCHEMA, PatchRequest | ||||
| from authentik.providers.scim.clients.schema import Group as SCIMGroupSchema | ||||
| from authentik.providers.scim.models import SCIMGroup, SCIMMapping, SCIMProvider, SCIMUser | ||||
| from authentik.providers.scim.models import ( | ||||
|     SCIMMapping, | ||||
|     SCIMProvider, | ||||
|     SCIMProviderGroup, | ||||
|     SCIMProviderUser, | ||||
| ) | ||||
|  | ||||
|  | ||||
| class SCIMGroupClient(SCIMClient[Group, SCIMGroup, SCIMGroupSchema]): | ||||
| class SCIMGroupClient(SCIMClient[Group, SCIMProviderGroup, SCIMGroupSchema]): | ||||
|     """SCIM client for groups""" | ||||
|  | ||||
|     connection_type = SCIMGroup | ||||
|     connection_type = SCIMProviderGroup | ||||
|     connection_type_query = "group" | ||||
|     mapper: PropertyMappingManager | ||||
|  | ||||
| @ -37,7 +42,7 @@ class SCIMGroupClient(SCIMClient[Group, SCIMGroup, SCIMGroupSchema]): | ||||
|             ["group", "provider", "connection"], | ||||
|         ) | ||||
|  | ||||
|     def to_schema(self, obj: Group, connection: SCIMGroup) -> SCIMGroupSchema: | ||||
|     def to_schema(self, obj: Group, connection: SCIMProviderGroup) -> SCIMGroupSchema: | ||||
|         """Convert authentik user into SCIM""" | ||||
|         raw_scim_group = super().to_schema( | ||||
|             obj, | ||||
| @ -52,7 +57,7 @@ class SCIMGroupClient(SCIMClient[Group, SCIMGroup, SCIMGroupSchema]): | ||||
|             scim_group.externalId = str(obj.pk) | ||||
|  | ||||
|         users = list(obj.users.order_by("id").values_list("id", flat=True)) | ||||
|         connections = SCIMUser.objects.filter(provider=self.provider, user__pk__in=users) | ||||
|         connections = SCIMProviderUser.objects.filter(provider=self.provider, user__pk__in=users) | ||||
|         members = [] | ||||
|         for user in connections: | ||||
|             members.append( | ||||
| @ -66,7 +71,7 @@ class SCIMGroupClient(SCIMClient[Group, SCIMGroup, SCIMGroupSchema]): | ||||
|  | ||||
|     def delete(self, obj: Group): | ||||
|         """Delete group""" | ||||
|         scim_group = SCIMGroup.objects.filter(provider=self.provider, group=obj).first() | ||||
|         scim_group = SCIMProviderGroup.objects.filter(provider=self.provider, group=obj).first() | ||||
|         if not scim_group: | ||||
|             self.logger.debug("Group does not exist in SCIM, skipping") | ||||
|             return None | ||||
| @ -88,9 +93,11 @@ class SCIMGroupClient(SCIMClient[Group, SCIMGroup, SCIMGroupSchema]): | ||||
|         scim_id = response.get("id") | ||||
|         if not scim_id or scim_id == "": | ||||
|             raise StopSync("SCIM Response with missing or invalid `id`") | ||||
|         return SCIMGroup.objects.create(provider=self.provider, group=group, scim_id=scim_id) | ||||
|         return SCIMProviderGroup.objects.create( | ||||
|             provider=self.provider, group=group, scim_id=scim_id | ||||
|         ) | ||||
|  | ||||
|     def update(self, group: Group, connection: SCIMGroup): | ||||
|     def update(self, group: Group, connection: SCIMProviderGroup): | ||||
|         """Update existing group""" | ||||
|         scim_group = self.to_schema(group, connection) | ||||
|         scim_group.id = connection.scim_id | ||||
| @ -158,16 +165,16 @@ class SCIMGroupClient(SCIMClient[Group, SCIMGroup, SCIMGroupSchema]): | ||||
|         """Add users in users_set to group""" | ||||
|         if len(users_set) < 1: | ||||
|             return | ||||
|         scim_group = SCIMGroup.objects.filter(provider=self.provider, group=group).first() | ||||
|         scim_group = SCIMProviderGroup.objects.filter(provider=self.provider, group=group).first() | ||||
|         if not scim_group: | ||||
|             self.logger.warning( | ||||
|                 "could not sync group membership, group does not exist", group=group | ||||
|             ) | ||||
|             return | ||||
|         user_ids = list( | ||||
|             SCIMUser.objects.filter(user__pk__in=users_set, provider=self.provider).values_list( | ||||
|                 "scim_id", flat=True | ||||
|             ) | ||||
|             SCIMProviderUser.objects.filter( | ||||
|                 user__pk__in=users_set, provider=self.provider | ||||
|             ).values_list("scim_id", flat=True) | ||||
|         ) | ||||
|         if len(user_ids) < 1: | ||||
|             return | ||||
| @ -184,16 +191,16 @@ class SCIMGroupClient(SCIMClient[Group, SCIMGroup, SCIMGroupSchema]): | ||||
|         """Remove users in users_set from group""" | ||||
|         if len(users_set) < 1: | ||||
|             return | ||||
|         scim_group = SCIMGroup.objects.filter(provider=self.provider, group=group).first() | ||||
|         scim_group = SCIMProviderGroup.objects.filter(provider=self.provider, group=group).first() | ||||
|         if not scim_group: | ||||
|             self.logger.warning( | ||||
|                 "could not sync group membership, group does not exist", group=group | ||||
|             ) | ||||
|             return | ||||
|         user_ids = list( | ||||
|             SCIMUser.objects.filter(user__pk__in=users_set, provider=self.provider).values_list( | ||||
|                 "scim_id", flat=True | ||||
|             ) | ||||
|             SCIMProviderUser.objects.filter( | ||||
|                 user__pk__in=users_set, provider=self.provider | ||||
|             ).values_list("scim_id", flat=True) | ||||
|         ) | ||||
|         if len(user_ids) < 1: | ||||
|             return | ||||
|  | ||||
| @ -9,13 +9,13 @@ from authentik.policies.utils import delete_none_values | ||||
| from authentik.providers.scim.clients.base import SCIMClient | ||||
| from authentik.providers.scim.clients.schema import SCIM_USER_SCHEMA | ||||
| from authentik.providers.scim.clients.schema import User as SCIMUserSchema | ||||
| from authentik.providers.scim.models import SCIMMapping, SCIMProvider, SCIMUser | ||||
| from authentik.providers.scim.models import SCIMMapping, SCIMProvider, SCIMProviderUser | ||||
|  | ||||
|  | ||||
| class SCIMUserClient(SCIMClient[User, SCIMUser, SCIMUserSchema]): | ||||
| class SCIMUserClient(SCIMClient[User, SCIMProviderUser, SCIMUserSchema]): | ||||
|     """SCIM client for users""" | ||||
|  | ||||
|     connection_type = SCIMUser | ||||
|     connection_type = SCIMProviderUser | ||||
|     connection_type_query = "user" | ||||
|     mapper: PropertyMappingManager | ||||
|  | ||||
| @ -27,7 +27,7 @@ class SCIMUserClient(SCIMClient[User, SCIMUser, SCIMUserSchema]): | ||||
|             ["provider", "connection"], | ||||
|         ) | ||||
|  | ||||
|     def to_schema(self, obj: User, connection: SCIMUser) -> SCIMUserSchema: | ||||
|     def to_schema(self, obj: User, connection: SCIMProviderUser) -> SCIMUserSchema: | ||||
|         """Convert authentik user into SCIM""" | ||||
|         raw_scim_user = super().to_schema( | ||||
|             obj, | ||||
| @ -44,7 +44,7 @@ class SCIMUserClient(SCIMClient[User, SCIMUser, SCIMUserSchema]): | ||||
|  | ||||
|     def delete(self, obj: User): | ||||
|         """Delete user""" | ||||
|         scim_user = SCIMUser.objects.filter(provider=self.provider, user=obj).first() | ||||
|         scim_user = SCIMProviderUser.objects.filter(provider=self.provider, user=obj).first() | ||||
|         if not scim_user: | ||||
|             self.logger.debug("User does not exist in SCIM, skipping") | ||||
|             return None | ||||
| @ -66,9 +66,9 @@ class SCIMUserClient(SCIMClient[User, SCIMUser, SCIMUserSchema]): | ||||
|         scim_id = response.get("id") | ||||
|         if not scim_id or scim_id == "": | ||||
|             raise StopSync("SCIM Response with missing or invalid `id`") | ||||
|         return SCIMUser.objects.create(provider=self.provider, user=user, scim_id=scim_id) | ||||
|         return SCIMProviderUser.objects.create(provider=self.provider, user=user, scim_id=scim_id) | ||||
|  | ||||
|     def update(self, user: User, connection: SCIMUser): | ||||
|     def update(self, user: User, connection: SCIMProviderUser): | ||||
|         """Update existing user""" | ||||
|         scim_user = self.to_schema(user, connection) | ||||
|         scim_user.id = connection.scim_id | ||||
|  | ||||
| @ -0,0 +1,24 @@ | ||||
| # Generated by Django 5.0.6 on 2024-06-04 07:45 | ||||
|  | ||||
| from django.conf import settings | ||||
| from django.db import migrations | ||||
|  | ||||
|  | ||||
| class Migration(migrations.Migration): | ||||
|  | ||||
|     dependencies = [ | ||||
|         ("authentik_core", "0035_alter_group_options_and_more"), | ||||
|         ("authentik_providers_scim", "0007_scimgroup_scim_id_scimuser_scim_id_and_more"), | ||||
|         migrations.swappable_dependency(settings.AUTH_USER_MODEL), | ||||
|     ] | ||||
|  | ||||
|     operations = [ | ||||
|         migrations.RenameModel( | ||||
|             old_name="SCIMGroup", | ||||
|             new_name="SCIMProviderGroup", | ||||
|         ), | ||||
|         migrations.RenameModel( | ||||
|             old_name="SCIMUser", | ||||
|             new_name="SCIMProviderUser", | ||||
|         ), | ||||
|     ] | ||||
| @ -10,6 +10,7 @@ from django.utils.translation import gettext_lazy as _ | ||||
| from rest_framework.serializers import Serializer | ||||
|  | ||||
| from authentik.core.models import BackchannelProvider, Group, PropertyMapping, User, UserTypes | ||||
| from authentik.lib.models import SerializerModel | ||||
| from authentik.lib.sync.outgoing.base import BaseOutgoingSyncClient | ||||
| from authentik.lib.sync.outgoing.models import OutgoingSyncProvider | ||||
|  | ||||
| @ -106,7 +107,7 @@ class SCIMMapping(PropertyMapping): | ||||
|         verbose_name_plural = _("SCIM Mappings") | ||||
|  | ||||
|  | ||||
| class SCIMUser(models.Model): | ||||
| class SCIMProviderUser(SerializerModel): | ||||
|     """Mapping of a user and provider to a SCIM user ID""" | ||||
|  | ||||
|     id = models.UUIDField(primary_key=True, editable=False, default=uuid4) | ||||
| @ -114,14 +115,20 @@ class SCIMUser(models.Model): | ||||
|     user = models.ForeignKey(User, on_delete=models.CASCADE) | ||||
|     provider = models.ForeignKey(SCIMProvider, on_delete=models.CASCADE) | ||||
|  | ||||
|     @property | ||||
|     def serializer(self) -> type[Serializer]: | ||||
|         from authentik.providers.scim.api.users import SCIMProviderUserSerializer | ||||
|  | ||||
|         return SCIMProviderUserSerializer | ||||
|  | ||||
|     class Meta: | ||||
|         unique_together = (("scim_id", "user", "provider"),) | ||||
|  | ||||
|     def __str__(self) -> str: | ||||
|         return f"SCIM User {self.user_id} to {self.provider_id}" | ||||
|         return f"SCIM Provider User {self.user_id} to {self.provider_id}" | ||||
|  | ||||
|  | ||||
| class SCIMGroup(models.Model): | ||||
| class SCIMProviderGroup(SerializerModel): | ||||
|     """Mapping of a group and provider to a SCIM user ID""" | ||||
|  | ||||
|     id = models.UUIDField(primary_key=True, editable=False, default=uuid4) | ||||
| @ -129,8 +136,14 @@ class SCIMGroup(models.Model): | ||||
|     group = models.ForeignKey(Group, on_delete=models.CASCADE) | ||||
|     provider = models.ForeignKey(SCIMProvider, on_delete=models.CASCADE) | ||||
|  | ||||
|     @property | ||||
|     def serializer(self) -> type[Serializer]: | ||||
|         from authentik.providers.scim.api.groups import SCIMProviderGroupSerializer | ||||
|  | ||||
|         return SCIMProviderGroupSerializer | ||||
|  | ||||
|     class Meta: | ||||
|         unique_together = (("scim_id", "group", "provider"),) | ||||
|  | ||||
|     def __str__(self) -> str: | ||||
|         return f"SCIM Group {self.group_id} to {self.provider_id}" | ||||
|         return f"SCIM Provider Group {self.group_id} to {self.provider_id}" | ||||
|  | ||||
| @ -1,9 +1,17 @@ | ||||
| """API URLs""" | ||||
|  | ||||
| from authentik.providers.scim.api.groups import ( | ||||
|     SCIMProviderGroupViewSet, | ||||
| ) | ||||
| from authentik.providers.scim.api.property_mappings import SCIMMappingViewSet | ||||
| from authentik.providers.scim.api.providers import SCIMProviderViewSet | ||||
| from authentik.providers.scim.api.users import ( | ||||
|     SCIMProviderUserViewSet, | ||||
| ) | ||||
|  | ||||
| api_urlpatterns = [ | ||||
|     ("providers/scim", SCIMProviderViewSet), | ||||
|     ("providers/scim_users", SCIMProviderUserViewSet), | ||||
|     ("providers/scim_groups", SCIMProviderGroupViewSet), | ||||
|     ("propertymappings/scim", SCIMMappingViewSet), | ||||
| ] | ||||
|  | ||||
| @ -161,7 +161,6 @@ class BaseLDAPSynchronizer: | ||||
|                 dn=object_dn, | ||||
|                 source=self._source, | ||||
|             ): | ||||
|                 try: | ||||
|                 if isinstance(value, (bytes)): | ||||
|                     self._logger.warning("property mapping returned bytes", mapping=mapping) | ||||
|                     continue | ||||
|  | ||||
							
								
								
									
										531
									
								
								schema.yml
									
									
									
									
									
								
							
							
						
						
									
										531
									
								
								schema.yml
									
									
									
									
									
								
							| @ -19726,6 +19726,403 @@ paths: | ||||
|               schema: | ||||
|                 $ref: '#/components/schemas/GenericError' | ||||
|           description: '' | ||||
|   /providers/scim_groups/: | ||||
|     get: | ||||
|       operationId: providers_scim_groups_list | ||||
|       description: SCIMProviderGroup Viewset | ||||
|       parameters: | ||||
|       - in: query | ||||
|         name: group__group_uuid | ||||
|         schema: | ||||
|           type: string | ||||
|           format: uuid | ||||
|       - in: query | ||||
|         name: group__name | ||||
|         schema: | ||||
|           type: string | ||||
|       - name: ordering | ||||
|         required: false | ||||
|         in: query | ||||
|         description: Which field to use when ordering the results. | ||||
|         schema: | ||||
|           type: string | ||||
|       - name: page | ||||
|         required: false | ||||
|         in: query | ||||
|         description: A page number within the paginated result set. | ||||
|         schema: | ||||
|           type: integer | ||||
|       - name: page_size | ||||
|         required: false | ||||
|         in: query | ||||
|         description: Number of results to return per page. | ||||
|         schema: | ||||
|           type: integer | ||||
|       - in: query | ||||
|         name: provider__id | ||||
|         schema: | ||||
|           type: integer | ||||
|       - name: search | ||||
|         required: false | ||||
|         in: query | ||||
|         description: A search term. | ||||
|         schema: | ||||
|           type: string | ||||
|       tags: | ||||
|       - providers | ||||
|       security: | ||||
|       - authentik: [] | ||||
|       responses: | ||||
|         '200': | ||||
|           content: | ||||
|             application/json: | ||||
|               schema: | ||||
|                 $ref: '#/components/schemas/PaginatedSCIMProviderGroupList' | ||||
|           description: '' | ||||
|         '400': | ||||
|           content: | ||||
|             application/json: | ||||
|               schema: | ||||
|                 $ref: '#/components/schemas/ValidationError' | ||||
|           description: '' | ||||
|         '403': | ||||
|           content: | ||||
|             application/json: | ||||
|               schema: | ||||
|                 $ref: '#/components/schemas/GenericError' | ||||
|           description: '' | ||||
|     post: | ||||
|       operationId: providers_scim_groups_create | ||||
|       description: SCIMProviderGroup Viewset | ||||
|       tags: | ||||
|       - providers | ||||
|       requestBody: | ||||
|         content: | ||||
|           application/json: | ||||
|             schema: | ||||
|               $ref: '#/components/schemas/SCIMProviderGroupRequest' | ||||
|         required: true | ||||
|       security: | ||||
|       - authentik: [] | ||||
|       responses: | ||||
|         '201': | ||||
|           content: | ||||
|             application/json: | ||||
|               schema: | ||||
|                 $ref: '#/components/schemas/SCIMProviderGroup' | ||||
|           description: '' | ||||
|         '400': | ||||
|           content: | ||||
|             application/json: | ||||
|               schema: | ||||
|                 $ref: '#/components/schemas/ValidationError' | ||||
|           description: '' | ||||
|         '403': | ||||
|           content: | ||||
|             application/json: | ||||
|               schema: | ||||
|                 $ref: '#/components/schemas/GenericError' | ||||
|           description: '' | ||||
|   /providers/scim_groups/{id}/: | ||||
|     get: | ||||
|       operationId: providers_scim_groups_retrieve | ||||
|       description: SCIMProviderGroup Viewset | ||||
|       parameters: | ||||
|       - in: path | ||||
|         name: id | ||||
|         schema: | ||||
|           type: string | ||||
|           format: uuid | ||||
|         description: A UUID string identifying this scim provider group. | ||||
|         required: true | ||||
|       tags: | ||||
|       - providers | ||||
|       security: | ||||
|       - authentik: [] | ||||
|       responses: | ||||
|         '200': | ||||
|           content: | ||||
|             application/json: | ||||
|               schema: | ||||
|                 $ref: '#/components/schemas/SCIMProviderGroup' | ||||
|           description: '' | ||||
|         '400': | ||||
|           content: | ||||
|             application/json: | ||||
|               schema: | ||||
|                 $ref: '#/components/schemas/ValidationError' | ||||
|           description: '' | ||||
|         '403': | ||||
|           content: | ||||
|             application/json: | ||||
|               schema: | ||||
|                 $ref: '#/components/schemas/GenericError' | ||||
|           description: '' | ||||
|     delete: | ||||
|       operationId: providers_scim_groups_destroy | ||||
|       description: SCIMProviderGroup Viewset | ||||
|       parameters: | ||||
|       - in: path | ||||
|         name: id | ||||
|         schema: | ||||
|           type: string | ||||
|           format: uuid | ||||
|         description: A UUID string identifying this scim provider group. | ||||
|         required: true | ||||
|       tags: | ||||
|       - providers | ||||
|       security: | ||||
|       - authentik: [] | ||||
|       responses: | ||||
|         '204': | ||||
|           description: No response body | ||||
|         '400': | ||||
|           content: | ||||
|             application/json: | ||||
|               schema: | ||||
|                 $ref: '#/components/schemas/ValidationError' | ||||
|           description: '' | ||||
|         '403': | ||||
|           content: | ||||
|             application/json: | ||||
|               schema: | ||||
|                 $ref: '#/components/schemas/GenericError' | ||||
|           description: '' | ||||
|   /providers/scim_groups/{id}/used_by/: | ||||
|     get: | ||||
|       operationId: providers_scim_groups_used_by_list | ||||
|       description: Get a list of all objects that use this object | ||||
|       parameters: | ||||
|       - in: path | ||||
|         name: id | ||||
|         schema: | ||||
|           type: string | ||||
|           format: uuid | ||||
|         description: A UUID string identifying this scim provider group. | ||||
|         required: true | ||||
|       tags: | ||||
|       - providers | ||||
|       security: | ||||
|       - authentik: [] | ||||
|       responses: | ||||
|         '200': | ||||
|           content: | ||||
|             application/json: | ||||
|               schema: | ||||
|                 type: array | ||||
|                 items: | ||||
|                   $ref: '#/components/schemas/UsedBy' | ||||
|           description: '' | ||||
|         '400': | ||||
|           content: | ||||
|             application/json: | ||||
|               schema: | ||||
|                 $ref: '#/components/schemas/ValidationError' | ||||
|           description: '' | ||||
|         '403': | ||||
|           content: | ||||
|             application/json: | ||||
|               schema: | ||||
|                 $ref: '#/components/schemas/GenericError' | ||||
|           description: '' | ||||
|   /providers/scim_users/: | ||||
|     get: | ||||
|       operationId: providers_scim_users_list | ||||
|       description: SCIMProviderUser Viewset | ||||
|       parameters: | ||||
|       - name: ordering | ||||
|         required: false | ||||
|         in: query | ||||
|         description: Which field to use when ordering the results. | ||||
|         schema: | ||||
|           type: string | ||||
|       - name: page | ||||
|         required: false | ||||
|         in: query | ||||
|         description: A page number within the paginated result set. | ||||
|         schema: | ||||
|           type: integer | ||||
|       - name: page_size | ||||
|         required: false | ||||
|         in: query | ||||
|         description: Number of results to return per page. | ||||
|         schema: | ||||
|           type: integer | ||||
|       - in: query | ||||
|         name: provider__id | ||||
|         schema: | ||||
|           type: integer | ||||
|       - name: search | ||||
|         required: false | ||||
|         in: query | ||||
|         description: A search term. | ||||
|         schema: | ||||
|           type: string | ||||
|       - in: query | ||||
|         name: user__id | ||||
|         schema: | ||||
|           type: integer | ||||
|       - in: query | ||||
|         name: user__username | ||||
|         schema: | ||||
|           type: string | ||||
|       tags: | ||||
|       - providers | ||||
|       security: | ||||
|       - authentik: [] | ||||
|       responses: | ||||
|         '200': | ||||
|           content: | ||||
|             application/json: | ||||
|               schema: | ||||
|                 $ref: '#/components/schemas/PaginatedSCIMProviderUserList' | ||||
|           description: '' | ||||
|         '400': | ||||
|           content: | ||||
|             application/json: | ||||
|               schema: | ||||
|                 $ref: '#/components/schemas/ValidationError' | ||||
|           description: '' | ||||
|         '403': | ||||
|           content: | ||||
|             application/json: | ||||
|               schema: | ||||
|                 $ref: '#/components/schemas/GenericError' | ||||
|           description: '' | ||||
|     post: | ||||
|       operationId: providers_scim_users_create | ||||
|       description: SCIMProviderUser Viewset | ||||
|       tags: | ||||
|       - providers | ||||
|       requestBody: | ||||
|         content: | ||||
|           application/json: | ||||
|             schema: | ||||
|               $ref: '#/components/schemas/SCIMProviderUserRequest' | ||||
|         required: true | ||||
|       security: | ||||
|       - authentik: [] | ||||
|       responses: | ||||
|         '201': | ||||
|           content: | ||||
|             application/json: | ||||
|               schema: | ||||
|                 $ref: '#/components/schemas/SCIMProviderUser' | ||||
|           description: '' | ||||
|         '400': | ||||
|           content: | ||||
|             application/json: | ||||
|               schema: | ||||
|                 $ref: '#/components/schemas/ValidationError' | ||||
|           description: '' | ||||
|         '403': | ||||
|           content: | ||||
|             application/json: | ||||
|               schema: | ||||
|                 $ref: '#/components/schemas/GenericError' | ||||
|           description: '' | ||||
|   /providers/scim_users/{id}/: | ||||
|     get: | ||||
|       operationId: providers_scim_users_retrieve | ||||
|       description: SCIMProviderUser Viewset | ||||
|       parameters: | ||||
|       - in: path | ||||
|         name: id | ||||
|         schema: | ||||
|           type: string | ||||
|           format: uuid | ||||
|         description: A UUID string identifying this scim provider user. | ||||
|         required: true | ||||
|       tags: | ||||
|       - providers | ||||
|       security: | ||||
|       - authentik: [] | ||||
|       responses: | ||||
|         '200': | ||||
|           content: | ||||
|             application/json: | ||||
|               schema: | ||||
|                 $ref: '#/components/schemas/SCIMProviderUser' | ||||
|           description: '' | ||||
|         '400': | ||||
|           content: | ||||
|             application/json: | ||||
|               schema: | ||||
|                 $ref: '#/components/schemas/ValidationError' | ||||
|           description: '' | ||||
|         '403': | ||||
|           content: | ||||
|             application/json: | ||||
|               schema: | ||||
|                 $ref: '#/components/schemas/GenericError' | ||||
|           description: '' | ||||
|     delete: | ||||
|       operationId: providers_scim_users_destroy | ||||
|       description: SCIMProviderUser Viewset | ||||
|       parameters: | ||||
|       - in: path | ||||
|         name: id | ||||
|         schema: | ||||
|           type: string | ||||
|           format: uuid | ||||
|         description: A UUID string identifying this scim provider user. | ||||
|         required: true | ||||
|       tags: | ||||
|       - providers | ||||
|       security: | ||||
|       - authentik: [] | ||||
|       responses: | ||||
|         '204': | ||||
|           description: No response body | ||||
|         '400': | ||||
|           content: | ||||
|             application/json: | ||||
|               schema: | ||||
|                 $ref: '#/components/schemas/ValidationError' | ||||
|           description: '' | ||||
|         '403': | ||||
|           content: | ||||
|             application/json: | ||||
|               schema: | ||||
|                 $ref: '#/components/schemas/GenericError' | ||||
|           description: '' | ||||
|   /providers/scim_users/{id}/used_by/: | ||||
|     get: | ||||
|       operationId: providers_scim_users_used_by_list | ||||
|       description: Get a list of all objects that use this object | ||||
|       parameters: | ||||
|       - in: path | ||||
|         name: id | ||||
|         schema: | ||||
|           type: string | ||||
|           format: uuid | ||||
|         description: A UUID string identifying this scim provider user. | ||||
|         required: true | ||||
|       tags: | ||||
|       - providers | ||||
|       security: | ||||
|       - authentik: [] | ||||
|       responses: | ||||
|         '200': | ||||
|           content: | ||||
|             application/json: | ||||
|               schema: | ||||
|                 type: array | ||||
|                 items: | ||||
|                   $ref: '#/components/schemas/UsedBy' | ||||
|           description: '' | ||||
|         '400': | ||||
|           content: | ||||
|             application/json: | ||||
|               schema: | ||||
|                 $ref: '#/components/schemas/ValidationError' | ||||
|           description: '' | ||||
|         '403': | ||||
|           content: | ||||
|             application/json: | ||||
|               schema: | ||||
|                 $ref: '#/components/schemas/GenericError' | ||||
|           description: '' | ||||
|   /rac/connection_tokens/: | ||||
|     get: | ||||
|       operationId: rac_connection_tokens_list | ||||
| @ -36335,6 +36732,8 @@ components: | ||||
|           type: string | ||||
|           format: uuid | ||||
|           readOnly: true | ||||
|         google_id: | ||||
|           type: string | ||||
|         group: | ||||
|           type: string | ||||
|           format: uuid | ||||
| @ -36348,6 +36747,7 @@ components: | ||||
|           readOnly: true | ||||
|       required: | ||||
|       - attributes | ||||
|       - google_id | ||||
|       - group | ||||
|       - group_obj | ||||
|       - id | ||||
| @ -36356,12 +36756,16 @@ components: | ||||
|       type: object | ||||
|       description: GoogleWorkspaceProviderGroup Serializer | ||||
|       properties: | ||||
|         google_id: | ||||
|           type: string | ||||
|           minLength: 1 | ||||
|         group: | ||||
|           type: string | ||||
|           format: uuid | ||||
|         provider: | ||||
|           type: integer | ||||
|       required: | ||||
|       - google_id | ||||
|       - group | ||||
|       - provider | ||||
|     GoogleWorkspaceProviderMapping: | ||||
| @ -36484,6 +36888,8 @@ components: | ||||
|           type: string | ||||
|           format: uuid | ||||
|           readOnly: true | ||||
|         google_id: | ||||
|           type: string | ||||
|         user: | ||||
|           type: integer | ||||
|         user_obj: | ||||
| @ -36496,6 +36902,7 @@ components: | ||||
|           readOnly: true | ||||
|       required: | ||||
|       - attributes | ||||
|       - google_id | ||||
|       - id | ||||
|       - provider | ||||
|       - user | ||||
| @ -36504,11 +36911,15 @@ components: | ||||
|       type: object | ||||
|       description: GoogleWorkspaceProviderUser Serializer | ||||
|       properties: | ||||
|         google_id: | ||||
|           type: string | ||||
|           minLength: 1 | ||||
|         user: | ||||
|           type: integer | ||||
|         provider: | ||||
|           type: integer | ||||
|       required: | ||||
|       - google_id | ||||
|       - provider | ||||
|       - user | ||||
|     Group: | ||||
| @ -38003,6 +38414,8 @@ components: | ||||
|           type: string | ||||
|           format: uuid | ||||
|           readOnly: true | ||||
|         microsoft_id: | ||||
|           type: string | ||||
|         group: | ||||
|           type: string | ||||
|           format: uuid | ||||
| @ -38019,11 +38432,15 @@ components: | ||||
|       - group | ||||
|       - group_obj | ||||
|       - id | ||||
|       - microsoft_id | ||||
|       - provider | ||||
|     MicrosoftEntraProviderGroupRequest: | ||||
|       type: object | ||||
|       description: MicrosoftEntraProviderGroup Serializer | ||||
|       properties: | ||||
|         microsoft_id: | ||||
|           type: string | ||||
|           minLength: 1 | ||||
|         group: | ||||
|           type: string | ||||
|           format: uuid | ||||
| @ -38031,6 +38448,7 @@ components: | ||||
|           type: integer | ||||
|       required: | ||||
|       - group | ||||
|       - microsoft_id | ||||
|       - provider | ||||
|     MicrosoftEntraProviderMapping: | ||||
|       type: object | ||||
| @ -38149,6 +38567,8 @@ components: | ||||
|           type: string | ||||
|           format: uuid | ||||
|           readOnly: true | ||||
|         microsoft_id: | ||||
|           type: string | ||||
|         user: | ||||
|           type: integer | ||||
|         user_obj: | ||||
| @ -38162,6 +38582,7 @@ components: | ||||
|       required: | ||||
|       - attributes | ||||
|       - id | ||||
|       - microsoft_id | ||||
|       - provider | ||||
|       - user | ||||
|       - user_obj | ||||
| @ -38169,11 +38590,15 @@ components: | ||||
|       type: object | ||||
|       description: MicrosoftEntraProviderUser Serializer | ||||
|       properties: | ||||
|         microsoft_id: | ||||
|           type: string | ||||
|           minLength: 1 | ||||
|         user: | ||||
|           type: integer | ||||
|         provider: | ||||
|           type: integer | ||||
|       required: | ||||
|       - microsoft_id | ||||
|       - provider | ||||
|       - user | ||||
|     ModelEnum: | ||||
| @ -40166,6 +40591,18 @@ components: | ||||
|       required: | ||||
|       - pagination | ||||
|       - results | ||||
|     PaginatedSCIMProviderGroupList: | ||||
|       type: object | ||||
|       properties: | ||||
|         pagination: | ||||
|           $ref: '#/components/schemas/Pagination' | ||||
|         results: | ||||
|           type: array | ||||
|           items: | ||||
|             $ref: '#/components/schemas/SCIMProviderGroup' | ||||
|       required: | ||||
|       - pagination | ||||
|       - results | ||||
|     PaginatedSCIMProviderList: | ||||
|       type: object | ||||
|       properties: | ||||
| @ -40178,6 +40615,18 @@ components: | ||||
|       required: | ||||
|       - pagination | ||||
|       - results | ||||
|     PaginatedSCIMProviderUserList: | ||||
|       type: object | ||||
|       properties: | ||||
|         pagination: | ||||
|           $ref: '#/components/schemas/Pagination' | ||||
|         results: | ||||
|           type: array | ||||
|           items: | ||||
|             $ref: '#/components/schemas/SCIMProviderUser' | ||||
|       required: | ||||
|       - pagination | ||||
|       - results | ||||
|     PaginatedSCIMSourceGroupList: | ||||
|       type: object | ||||
|       properties: | ||||
| @ -44147,12 +44596,14 @@ components: | ||||
|       properties: | ||||
|         user: | ||||
|           type: integer | ||||
|           nullable: true | ||||
|         context: | ||||
|           type: object | ||||
|           additionalProperties: {} | ||||
|         group: | ||||
|           type: string | ||||
|           format: uuid | ||||
|           nullable: true | ||||
|     PropertyMappingTestResult: | ||||
|       type: object | ||||
|       description: Result of a Property-mapping test | ||||
| @ -45906,6 +46357,47 @@ components: | ||||
|       - url | ||||
|       - verbose_name | ||||
|       - verbose_name_plural | ||||
|     SCIMProviderGroup: | ||||
|       type: object | ||||
|       description: SCIMProviderGroup Serializer | ||||
|       properties: | ||||
|         id: | ||||
|           type: string | ||||
|           format: uuid | ||||
|           readOnly: true | ||||
|         scim_id: | ||||
|           type: string | ||||
|         group: | ||||
|           type: string | ||||
|           format: uuid | ||||
|         group_obj: | ||||
|           allOf: | ||||
|           - $ref: '#/components/schemas/UserGroup' | ||||
|           readOnly: true | ||||
|         provider: | ||||
|           type: integer | ||||
|       required: | ||||
|       - group | ||||
|       - group_obj | ||||
|       - id | ||||
|       - provider | ||||
|       - scim_id | ||||
|     SCIMProviderGroupRequest: | ||||
|       type: object | ||||
|       description: SCIMProviderGroup Serializer | ||||
|       properties: | ||||
|         scim_id: | ||||
|           type: string | ||||
|           minLength: 1 | ||||
|         group: | ||||
|           type: string | ||||
|           format: uuid | ||||
|         provider: | ||||
|           type: integer | ||||
|       required: | ||||
|       - group | ||||
|       - provider | ||||
|       - scim_id | ||||
|     SCIMProviderRequest: | ||||
|       type: object | ||||
|       description: SCIMProvider Serializer | ||||
| @ -45942,6 +46434,45 @@ components: | ||||
|       - name | ||||
|       - token | ||||
|       - url | ||||
|     SCIMProviderUser: | ||||
|       type: object | ||||
|       description: SCIMProviderUser Serializer | ||||
|       properties: | ||||
|         id: | ||||
|           type: string | ||||
|           format: uuid | ||||
|           readOnly: true | ||||
|         scim_id: | ||||
|           type: string | ||||
|         user: | ||||
|           type: integer | ||||
|         user_obj: | ||||
|           allOf: | ||||
|           - $ref: '#/components/schemas/GroupMember' | ||||
|           readOnly: true | ||||
|         provider: | ||||
|           type: integer | ||||
|       required: | ||||
|       - id | ||||
|       - provider | ||||
|       - scim_id | ||||
|       - user | ||||
|       - user_obj | ||||
|     SCIMProviderUserRequest: | ||||
|       type: object | ||||
|       description: SCIMProviderUser Serializer | ||||
|       properties: | ||||
|         scim_id: | ||||
|           type: string | ||||
|           minLength: 1 | ||||
|         user: | ||||
|           type: integer | ||||
|         provider: | ||||
|           type: integer | ||||
|       required: | ||||
|       - provider | ||||
|       - scim_id | ||||
|       - user | ||||
|     SCIMSource: | ||||
|       type: object | ||||
|       description: SCIMSource Serializer | ||||
|  | ||||
| @ -126,6 +126,7 @@ export class PolicyTestForm extends Form<PropertyMappingTestRequest> { | ||||
|     renderForm(): TemplateResult { | ||||
|         return html`<ak-form-element-horizontal label=${msg("User")} name="user"> | ||||
|                 <ak-search-select | ||||
|                     blankable | ||||
|                     .fetchObjects=${async (query?: string): Promise<User[]> => { | ||||
|                         const args: CoreUsersListRequest = { | ||||
|                             ordering: "username", | ||||
| @ -153,6 +154,7 @@ export class PolicyTestForm extends Form<PropertyMappingTestRequest> { | ||||
|             </ak-form-element-horizontal> | ||||
|             <ak-form-element-horizontal label=${msg("Group")} name="group"> | ||||
|                 <ak-search-select | ||||
|                     blankable | ||||
|                     .fetchObjects=${async (query?: string): Promise<Group[]> => { | ||||
|                         const args: CoreGroupsListRequest = { | ||||
|                             ordering: "name", | ||||
|  | ||||
| @ -1,5 +1,6 @@ | ||||
| import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | ||||
| import { uiConfig } from "@goauthentik/common/ui/config"; | ||||
| import "@goauthentik/elements/forms/DeleteBulkForm"; | ||||
| import { PaginatedResponse, Table, TableColumn } from "@goauthentik/elements/table/Table"; | ||||
|  | ||||
| import { msg } from "@lit/localize"; | ||||
| @ -19,6 +20,26 @@ export class GoogleWorkspaceProviderGroupList extends Table<GoogleWorkspaceProvi | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     checkbox = true; | ||||
|     clearOnRefresh = true; | ||||
|  | ||||
|     renderToolbarSelected(): TemplateResult { | ||||
|         const disabled = this.selectedElements.length < 1; | ||||
|         return html`<ak-forms-delete-bulk | ||||
|             objectLabel=${msg("Google Workspace Group(s)")} | ||||
|             .objects=${this.selectedElements} | ||||
|             .delete=${(item: GoogleWorkspaceProviderGroup) => { | ||||
|                 return new ProvidersApi(DEFAULT_CONFIG).providersGoogleWorkspaceGroupsDestroy({ | ||||
|                     id: item.id, | ||||
|                 }); | ||||
|             }} | ||||
|         > | ||||
|             <button ?disabled=${disabled} slot="trigger" class="pf-c-button pf-m-danger"> | ||||
|                 ${msg("Delete")} | ||||
|             </button> | ||||
|         </ak-forms-delete-bulk>`; | ||||
|     } | ||||
|  | ||||
|     async apiEndpoint(page: number): Promise<PaginatedResponse<GoogleWorkspaceProviderGroup>> { | ||||
|         return new ProvidersApi(DEFAULT_CONFIG).providersGoogleWorkspaceGroupsList({ | ||||
|             page: page, | ||||
|  | ||||
| @ -1,5 +1,6 @@ | ||||
| import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | ||||
| import { uiConfig } from "@goauthentik/common/ui/config"; | ||||
| import "@goauthentik/elements/forms/DeleteBulkForm"; | ||||
| import { PaginatedResponse, Table, TableColumn } from "@goauthentik/elements/table/Table"; | ||||
|  | ||||
| import { msg } from "@lit/localize"; | ||||
| @ -19,6 +20,26 @@ export class GoogleWorkspaceProviderUserList extends Table<GoogleWorkspaceProvid | ||||
|  | ||||
|     expandable = true; | ||||
|  | ||||
|     checkbox = true; | ||||
|     clearOnRefresh = true; | ||||
|  | ||||
|     renderToolbarSelected(): TemplateResult { | ||||
|         const disabled = this.selectedElements.length < 1; | ||||
|         return html`<ak-forms-delete-bulk | ||||
|             objectLabel=${msg("Google Workspace User(s)")} | ||||
|             .objects=${this.selectedElements} | ||||
|             .delete=${(item: GoogleWorkspaceProviderUser) => { | ||||
|                 return new ProvidersApi(DEFAULT_CONFIG).providersGoogleWorkspaceUsersDestroy({ | ||||
|                     id: item.id, | ||||
|                 }); | ||||
|             }} | ||||
|         > | ||||
|             <button ?disabled=${disabled} slot="trigger" class="pf-c-button pf-m-danger"> | ||||
|                 ${msg("Delete")} | ||||
|             </button> | ||||
|         </ak-forms-delete-bulk>`; | ||||
|     } | ||||
|  | ||||
|     async apiEndpoint(page: number): Promise<PaginatedResponse<GoogleWorkspaceProviderUser>> { | ||||
|         return new ProvidersApi(DEFAULT_CONFIG).providersGoogleWorkspaceUsersList({ | ||||
|             page: page, | ||||
|  | ||||
| @ -1,5 +1,6 @@ | ||||
| import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | ||||
| import { uiConfig } from "@goauthentik/common/ui/config"; | ||||
| import "@goauthentik/elements/forms/DeleteBulkForm"; | ||||
| import { PaginatedResponse, Table, TableColumn } from "@goauthentik/elements/table/Table"; | ||||
|  | ||||
| import { msg } from "@lit/localize"; | ||||
| @ -19,6 +20,23 @@ export class MicrosoftEntraProviderGroupList extends Table<MicrosoftEntraProvide | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     renderToolbarSelected(): TemplateResult { | ||||
|         const disabled = this.selectedElements.length < 1; | ||||
|         return html`<ak-forms-delete-bulk | ||||
|             objectLabel=${msg("Microsoft Entra Group(s)")} | ||||
|             .objects=${this.selectedElements} | ||||
|             .delete=${(item: MicrosoftEntraProviderGroup) => { | ||||
|                 return new ProvidersApi(DEFAULT_CONFIG).providersMicrosoftEntraGroupsDestroy({ | ||||
|                     id: item.id, | ||||
|                 }); | ||||
|             }} | ||||
|         > | ||||
|             <button ?disabled=${disabled} slot="trigger" class="pf-c-button pf-m-danger"> | ||||
|                 ${msg("Delete")} | ||||
|             </button> | ||||
|         </ak-forms-delete-bulk>`; | ||||
|     } | ||||
|  | ||||
|     async apiEndpoint(page: number): Promise<PaginatedResponse<MicrosoftEntraProviderGroup>> { | ||||
|         return new ProvidersApi(DEFAULT_CONFIG).providersMicrosoftEntraGroupsList({ | ||||
|             page: page, | ||||
|  | ||||
| @ -1,5 +1,6 @@ | ||||
| import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | ||||
| import { uiConfig } from "@goauthentik/common/ui/config"; | ||||
| import "@goauthentik/elements/forms/DeleteBulkForm"; | ||||
| import { PaginatedResponse, Table, TableColumn } from "@goauthentik/elements/table/Table"; | ||||
|  | ||||
| import { msg } from "@lit/localize"; | ||||
| @ -19,6 +20,26 @@ export class MicrosoftEntraProviderUserList extends Table<MicrosoftEntraProvider | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     checkbox = true; | ||||
|     clearOnRefresh = true; | ||||
|  | ||||
|     renderToolbarSelected(): TemplateResult { | ||||
|         const disabled = this.selectedElements.length < 1; | ||||
|         return html`<ak-forms-delete-bulk | ||||
|             objectLabel=${msg("Microsoft Entra User(s)")} | ||||
|             .objects=${this.selectedElements} | ||||
|             .delete=${(item: MicrosoftEntraProviderUser) => { | ||||
|                 return new ProvidersApi(DEFAULT_CONFIG).providersMicrosoftEntraUsersDestroy({ | ||||
|                     id: item.id, | ||||
|                 }); | ||||
|             }} | ||||
|         > | ||||
|             <button ?disabled=${disabled} slot="trigger" class="pf-c-button pf-m-danger"> | ||||
|                 ${msg("Delete")} | ||||
|             </button> | ||||
|         </ak-forms-delete-bulk>`; | ||||
|     } | ||||
|  | ||||
|     async apiEndpoint(page: number): Promise<PaginatedResponse<MicrosoftEntraProviderUser>> { | ||||
|         return new ProvidersApi(DEFAULT_CONFIG).providersMicrosoftEntraUsersList({ | ||||
|             page: page, | ||||
|  | ||||
							
								
								
									
										63
									
								
								web/src/admin/providers/scim/SCIMProviderGroupList.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								web/src/admin/providers/scim/SCIMProviderGroupList.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,63 @@ | ||||
| import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | ||||
| import { uiConfig } from "@goauthentik/common/ui/config"; | ||||
| import "@goauthentik/elements/forms/DeleteBulkForm"; | ||||
| import { PaginatedResponse, Table, TableColumn } from "@goauthentik/elements/table/Table"; | ||||
|  | ||||
| import { msg } from "@lit/localize"; | ||||
| import { TemplateResult, html } from "lit"; | ||||
| import { customElement, property } from "lit/decorators.js"; | ||||
|  | ||||
| import { ProvidersApi, SCIMProviderGroup } from "@goauthentik/api"; | ||||
|  | ||||
| @customElement("ak-provider-scim-groups-list") | ||||
| export class SCIMProviderGroupList extends Table<SCIMProviderGroup> { | ||||
|     @property({ type: Number }) | ||||
|     providerId?: number; | ||||
|  | ||||
|     searchEnabled(): boolean { | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     checkbox = true; | ||||
|     clearOnRefresh = true; | ||||
|  | ||||
|     renderToolbarSelected(): TemplateResult { | ||||
|         const disabled = this.selectedElements.length < 1; | ||||
|         return html`<ak-forms-delete-bulk | ||||
|             objectLabel=${msg("SCIM Group(s)")} | ||||
|             .objects=${this.selectedElements} | ||||
|             .delete=${(item: SCIMProviderGroup) => { | ||||
|                 return new ProvidersApi(DEFAULT_CONFIG).providersScimGroupsDestroy({ | ||||
|                     id: item.id, | ||||
|                 }); | ||||
|             }} | ||||
|         > | ||||
|             <button ?disabled=${disabled} slot="trigger" class="pf-c-button pf-m-danger"> | ||||
|                 ${msg("Delete")} | ||||
|             </button> | ||||
|         </ak-forms-delete-bulk>`; | ||||
|     } | ||||
|  | ||||
|     async apiEndpoint(page: number): Promise<PaginatedResponse<SCIMProviderGroup>> { | ||||
|         return new ProvidersApi(DEFAULT_CONFIG).providersScimGroupsList({ | ||||
|             page: page, | ||||
|             pageSize: (await uiConfig()).pagination.perPage, | ||||
|             ordering: this.order, | ||||
|             search: this.search || "", | ||||
|             providerId: this.providerId, | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     columns(): TableColumn[] { | ||||
|         return [new TableColumn(msg("Name")), new TableColumn(msg("ID"))]; | ||||
|     } | ||||
|  | ||||
|     row(item: SCIMProviderGroup): TemplateResult[] { | ||||
|         return [ | ||||
|             html`<a href="#/identity/groups/${item.groupObj.pk}"> | ||||
|                 <div>${item.groupObj.name}</div> | ||||
|             </a>`, | ||||
|             html`${item.id}`, | ||||
|         ]; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										64
									
								
								web/src/admin/providers/scim/SCIMProviderUserList.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								web/src/admin/providers/scim/SCIMProviderUserList.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,64 @@ | ||||
| import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | ||||
| import { uiConfig } from "@goauthentik/common/ui/config"; | ||||
| import "@goauthentik/elements/forms/DeleteBulkForm"; | ||||
| import { PaginatedResponse, Table, TableColumn } from "@goauthentik/elements/table/Table"; | ||||
|  | ||||
| import { msg } from "@lit/localize"; | ||||
| import { TemplateResult, html } from "lit"; | ||||
| import { customElement, property } from "lit/decorators.js"; | ||||
|  | ||||
| import { ProvidersApi, SCIMProviderUser } from "@goauthentik/api"; | ||||
|  | ||||
| @customElement("ak-provider-google-workspace-users-list") | ||||
| export class SCIMProviderUserList extends Table<SCIMProviderUser> { | ||||
|     @property({ type: Number }) | ||||
|     providerId?: number; | ||||
|  | ||||
|     searchEnabled(): boolean { | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     checkbox = true; | ||||
|     clearOnRefresh = true; | ||||
|  | ||||
|     renderToolbarSelected(): TemplateResult { | ||||
|         const disabled = this.selectedElements.length < 1; | ||||
|         return html`<ak-forms-delete-bulk | ||||
|             objectLabel=${msg("SCIM User(s)")} | ||||
|             .objects=${this.selectedElements} | ||||
|             .delete=${(item: SCIMProviderUser) => { | ||||
|                 return new ProvidersApi(DEFAULT_CONFIG).providersScimUsersDestroy({ | ||||
|                     id: item.id, | ||||
|                 }); | ||||
|             }} | ||||
|         > | ||||
|             <button ?disabled=${disabled} slot="trigger" class="pf-c-button pf-m-danger"> | ||||
|                 ${msg("Delete")} | ||||
|             </button> | ||||
|         </ak-forms-delete-bulk>`; | ||||
|     } | ||||
|  | ||||
|     async apiEndpoint(page: number): Promise<PaginatedResponse<SCIMProviderUser>> { | ||||
|         return new ProvidersApi(DEFAULT_CONFIG).providersScimUsersList({ | ||||
|             page: page, | ||||
|             pageSize: (await uiConfig()).pagination.perPage, | ||||
|             ordering: this.order, | ||||
|             search: this.search || "", | ||||
|             providerId: this.providerId, | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     columns(): TableColumn[] { | ||||
|         return [new TableColumn(msg("Username")), new TableColumn(msg("ID"))]; | ||||
|     } | ||||
|  | ||||
|     row(item: SCIMProviderUser): TemplateResult[] { | ||||
|         return [ | ||||
|             html`<a href="#/identity/users/${item.userObj.pk}"> | ||||
|                 <div>${item.userObj.username}</div> | ||||
|                 <small>${item.userObj.name}</small> | ||||
|             </a>`, | ||||
|             html`${item.id}`, | ||||
|         ]; | ||||
|     } | ||||
| } | ||||
| @ -1,4 +1,6 @@ | ||||
| import "@goauthentik/admin/providers/scim/SCIMProviderForm"; | ||||
| import "@goauthentik/admin/providers/scim/SCIMProviderGroupList"; | ||||
| import "@goauthentik/admin/providers/scim/SCIMProviderUserList"; | ||||
| import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | ||||
| import { EVENT_REFRESH } from "@goauthentik/common/constants"; | ||||
| import "@goauthentik/components/events/ObjectChangelog"; | ||||
| @ -102,6 +104,28 @@ export class SCIMProviderViewPage extends AKElement { | ||||
|                     </div> | ||||
|                 </div> | ||||
|             </section> | ||||
|             <section | ||||
|                 slot="page-users" | ||||
|                 data-tab-title="${msg("Provisioned Users")}" | ||||
|                 class="pf-c-page__main-section pf-m-no-padding-mobile" | ||||
|             > | ||||
|                 <div class="pf-l-grid pf-m-gutter"> | ||||
|                     <ak-provider-scim-users-list | ||||
|                         providerId=${this.provider.pk} | ||||
|                     ></ak-provider-scim-users-list> | ||||
|                 </div> | ||||
|             </section> | ||||
|             <section | ||||
|                 slot="page-groups" | ||||
|                 data-tab-title="${msg("Provisioned Groups")}" | ||||
|                 class="pf-c-page__main-section pf-m-no-padding-mobile" | ||||
|             > | ||||
|                 <div class="pf-l-grid pf-m-gutter"> | ||||
|                     <ak-provider-scim-groups-list | ||||
|                         providerId=${this.provider.pk} | ||||
|                     ></ak-provider-scim-groups-list> | ||||
|                 </div> | ||||
|             </section> | ||||
|             <ak-rbac-object-permission-page | ||||
|                 slot="page-permissions" | ||||
|                 data-tab-title="${msg("Permissions")}" | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 Jens L
					Jens L