From bb20576d844fd36d724a732188314d9a980fe8e3 Mon Sep 17 00:00:00 2001 From: "Jens L." Date: Tue, 18 Mar 2025 13:35:56 +0000 Subject: [PATCH] providers/scim: save attributes returned from remote system like google workspace and entra ID (#13459) providers/scim: save attributes returned from remote system like google workspace and entra Signed-off-by: Jens Langhammer --- authentik/providers/scim/api/groups.py | 2 ++ authentik/providers/scim/api/users.py | 2 ++ authentik/providers/scim/clients/groups.py | 2 +- authentik/providers/scim/clients/users.py | 11 ++++++--- ...2_scimprovidergroup_attributes_and_more.py | 23 +++++++++++++++++++ authentik/providers/scim/models.py | 2 ++ schema.yml | 6 +++++ .../providers/scim/SCIMProviderGroupList.ts | 8 +++++++ .../providers/scim/SCIMProviderUserList.ts | 8 +++++++ 9 files changed, 60 insertions(+), 4 deletions(-) create mode 100644 authentik/providers/scim/migrations/0012_scimprovidergroup_attributes_and_more.py diff --git a/authentik/providers/scim/api/groups.py b/authentik/providers/scim/api/groups.py index bfd1f44362..8a31da3e9c 100644 --- a/authentik/providers/scim/api/groups.py +++ b/authentik/providers/scim/api/groups.py @@ -24,7 +24,9 @@ class SCIMProviderGroupSerializer(ModelSerializer): "group", "group_obj", "provider", + "attributes", ] + extra_kwargs = {"attributes": {"read_only": True}} class SCIMProviderGroupViewSet( diff --git a/authentik/providers/scim/api/users.py b/authentik/providers/scim/api/users.py index 519f186478..f31574a2d4 100644 --- a/authentik/providers/scim/api/users.py +++ b/authentik/providers/scim/api/users.py @@ -24,7 +24,9 @@ class SCIMProviderUserSerializer(ModelSerializer): "user", "user_obj", "provider", + "attributes", ] + extra_kwargs = {"attributes": {"read_only": True}} class SCIMProviderUserViewSet( diff --git a/authentik/providers/scim/clients/groups.py b/authentik/providers/scim/clients/groups.py index 8221d7d131..6a0456ba0a 100644 --- a/authentik/providers/scim/clients/groups.py +++ b/authentik/providers/scim/clients/groups.py @@ -102,7 +102,7 @@ class SCIMGroupClient(SCIMClient[Group, SCIMProviderGroup, SCIMGroupSchema]): if not scim_id or scim_id == "": raise StopSync("SCIM Response with missing or invalid `id`") connection = SCIMProviderGroup.objects.create( - provider=self.provider, group=group, scim_id=scim_id + provider=self.provider, group=group, scim_id=scim_id, attributes=response ) users = list(group.users.order_by("id").values_list("id", flat=True)) self._patch_add_users(connection, users) diff --git a/authentik/providers/scim/clients/users.py b/authentik/providers/scim/clients/users.py index f9bfe58b88..ff11608ebe 100644 --- a/authentik/providers/scim/clients/users.py +++ b/authentik/providers/scim/clients/users.py @@ -77,21 +77,24 @@ class SCIMUserClient(SCIMClient[User, SCIMProviderUser, SCIMUserSchema]): if len(users_res) < 1: raise exc return SCIMProviderUser.objects.create( - provider=self.provider, user=user, scim_id=users_res[0]["id"] + provider=self.provider, + user=user, + scim_id=users_res[0]["id"], + attributes=users_res[0], ) else: scim_id = response.get("id") if not scim_id or scim_id == "": raise StopSync("SCIM Response with missing or invalid `id`") return SCIMProviderUser.objects.create( - provider=self.provider, user=user, scim_id=scim_id + provider=self.provider, user=user, scim_id=scim_id, attributes=response ) def update(self, user: User, connection: SCIMProviderUser): """Update existing user""" scim_user = self.to_schema(user, connection) scim_user.id = connection.scim_id - self._request( + response = self._request( "PUT", f"/Users/{connection.scim_id}", json=scim_user.model_dump( @@ -99,3 +102,5 @@ class SCIMUserClient(SCIMClient[User, SCIMProviderUser, SCIMUserSchema]): exclude_unset=True, ), ) + connection.attributes = response + connection.save() diff --git a/authentik/providers/scim/migrations/0012_scimprovidergroup_attributes_and_more.py b/authentik/providers/scim/migrations/0012_scimprovidergroup_attributes_and_more.py new file mode 100644 index 0000000000..689fcf2bd8 --- /dev/null +++ b/authentik/providers/scim/migrations/0012_scimprovidergroup_attributes_and_more.py @@ -0,0 +1,23 @@ +# Generated by Django 5.0.12 on 2025-03-11 13:51 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("authentik_providers_scim", "0011_scimprovider_dry_run"), + ] + + operations = [ + migrations.AddField( + model_name="scimprovidergroup", + name="attributes", + field=models.JSONField(default=dict), + ), + migrations.AddField( + model_name="scimprovideruser", + name="attributes", + field=models.JSONField(default=dict), + ), + ] diff --git a/authentik/providers/scim/models.py b/authentik/providers/scim/models.py index 8c85499a4a..09fbf16cb6 100644 --- a/authentik/providers/scim/models.py +++ b/authentik/providers/scim/models.py @@ -22,6 +22,7 @@ class SCIMProviderUser(SerializerModel): scim_id = models.TextField() user = models.ForeignKey(User, on_delete=models.CASCADE) provider = models.ForeignKey("SCIMProvider", on_delete=models.CASCADE) + attributes = models.JSONField(default=dict) @property def serializer(self) -> type[Serializer]: @@ -43,6 +44,7 @@ class SCIMProviderGroup(SerializerModel): scim_id = models.TextField() group = models.ForeignKey(Group, on_delete=models.CASCADE) provider = models.ForeignKey("SCIMProvider", on_delete=models.CASCADE) + attributes = models.JSONField(default=dict) @property def serializer(self) -> type[Serializer]: diff --git a/schema.yml b/schema.yml index 3c5331ead0..1283656f05 100644 --- a/schema.yml +++ b/schema.yml @@ -55897,7 +55897,10 @@ components: readOnly: true provider: type: integer + attributes: + readOnly: true required: + - attributes - group - group_obj - id @@ -55984,7 +55987,10 @@ components: readOnly: true provider: type: integer + attributes: + readOnly: true required: + - attributes - id - provider - scim_id diff --git a/web/src/admin/providers/scim/SCIMProviderGroupList.ts b/web/src/admin/providers/scim/SCIMProviderGroupList.ts index fedc38a7bf..cd0c1ca552 100644 --- a/web/src/admin/providers/scim/SCIMProviderGroupList.ts +++ b/web/src/admin/providers/scim/SCIMProviderGroupList.ts @@ -24,6 +24,7 @@ export class SCIMProviderGroupList extends Table { return true; } + expandable = true; checkbox = true; clearOnRefresh = true; @@ -81,6 +82,13 @@ export class SCIMProviderGroupList extends Table { html`${item.id}`, ]; } + renderExpanded(item: SCIMProviderGroup): TemplateResult { + return html` +
+
${JSON.stringify(item.attributes, null, 4)}
+
+ `; + } } declare global { diff --git a/web/src/admin/providers/scim/SCIMProviderUserList.ts b/web/src/admin/providers/scim/SCIMProviderUserList.ts index 3625b61097..1e28d1eecd 100644 --- a/web/src/admin/providers/scim/SCIMProviderUserList.ts +++ b/web/src/admin/providers/scim/SCIMProviderUserList.ts @@ -24,6 +24,7 @@ export class SCIMProviderUserList extends Table { return true; } + expandable = true; checkbox = true; clearOnRefresh = true; @@ -82,6 +83,13 @@ export class SCIMProviderUserList extends Table { html`${item.id}`, ]; } + renderExpanded(item: SCIMProviderUser): TemplateResult { + return html` +
+
${JSON.stringify(item.attributes, null, 4)}
+
+ `; + } } declare global {