From 51d3511f8b23b67d13a85fde5639353f4da51b1a Mon Sep 17 00:00:00 2001 From: Jens L Date: Thu, 16 Nov 2023 11:36:49 +0100 Subject: [PATCH] providers/scim: fix missing schemas attribute for User and Group (#7477) * providers/scim: fix missing schemas attribute for User and Group Signed-off-by: Jens Langhammer * make things actually work Signed-off-by: Jens Langhammer --------- Signed-off-by: Jens Langhammer --- authentik/providers/scim/clients/group.py | 4 +++- authentik/providers/scim/clients/schema.py | 2 ++ authentik/providers/scim/clients/user.py | 4 +++- authentik/providers/scim/tests/test_group.py | 18 ++++++++++++++--- .../providers/scim/tests/test_membership.py | 20 ++++++++++++++----- authentik/providers/scim/tests/test_user.py | 4 ++++ 6 files changed, 42 insertions(+), 10 deletions(-) diff --git a/authentik/providers/scim/clients/group.py b/authentik/providers/scim/clients/group.py index 98771315d..306cc21f9 100644 --- a/authentik/providers/scim/clients/group.py +++ b/authentik/providers/scim/clients/group.py @@ -46,7 +46,9 @@ class SCIMGroupClient(SCIMClient[Group, SCIMGroupSchema]): def to_scim(self, obj: Group) -> SCIMGroupSchema: """Convert authentik user into SCIM""" - raw_scim_group = {} + raw_scim_group = { + "schemas": ("urn:ietf:params:scim:schemas:core:2.0:Group",), + } for mapping in ( self.provider.property_mappings_group.all().order_by("name").select_subclasses() ): diff --git a/authentik/providers/scim/clients/schema.py b/authentik/providers/scim/clients/schema.py index b9cbe3d43..b1c268255 100644 --- a/authentik/providers/scim/clients/schema.py +++ b/authentik/providers/scim/clients/schema.py @@ -15,12 +15,14 @@ from pydanticscim.user import User as BaseUser class User(BaseUser): """Modified User schema with added externalId field""" + schemas: tuple[str] = ("urn:ietf:params:scim:schemas:core:2.0:User",) externalId: Optional[str] = None class Group(BaseGroup): """Modified Group schema with added externalId field""" + schemas: tuple[str] = ("urn:ietf:params:scim:schemas:core:2.0:Group",) externalId: Optional[str] = None diff --git a/authentik/providers/scim/clients/user.py b/authentik/providers/scim/clients/user.py index 31d912858..11ef6a159 100644 --- a/authentik/providers/scim/clients/user.py +++ b/authentik/providers/scim/clients/user.py @@ -39,7 +39,9 @@ class SCIMUserClient(SCIMClient[User, SCIMUserSchema]): def to_scim(self, obj: User) -> SCIMUserSchema: """Convert authentik user into SCIM""" - raw_scim_user = {} + raw_scim_user = { + "schemas": ("urn:ietf:params:scim:schemas:core:2.0:User",), + } for mapping in self.provider.property_mappings.all().order_by("name").select_subclasses(): if not isinstance(mapping, SCIMMapping): continue diff --git a/authentik/providers/scim/tests/test_group.py b/authentik/providers/scim/tests/test_group.py index 6004a453b..6dd9d70ca 100644 --- a/authentik/providers/scim/tests/test_group.py +++ b/authentik/providers/scim/tests/test_group.py @@ -61,7 +61,11 @@ class SCIMGroupTests(TestCase): self.assertEqual(mock.request_history[1].method, "POST") self.assertJSONEqual( mock.request_history[1].body, - {"externalId": str(group.pk), "displayName": group.name}, + { + "schemas": ["urn:ietf:params:scim:schemas:core:2.0:Group"], + "externalId": str(group.pk), + "displayName": group.name, + }, ) @Mocker() @@ -96,7 +100,11 @@ class SCIMGroupTests(TestCase): validate(body, loads(schema.read())) self.assertEqual( body, - {"externalId": str(group.pk), "displayName": group.name}, + { + "schemas": ["urn:ietf:params:scim:schemas:core:2.0:Group"], + "externalId": str(group.pk), + "displayName": group.name, + }, ) group.save() self.assertEqual(mock.call_count, 4) @@ -129,7 +137,11 @@ class SCIMGroupTests(TestCase): self.assertEqual(mock.request_history[1].method, "POST") self.assertJSONEqual( mock.request_history[1].body, - {"externalId": str(group.pk), "displayName": group.name}, + { + "schemas": ["urn:ietf:params:scim:schemas:core:2.0:Group"], + "externalId": str(group.pk), + "displayName": group.name, + }, ) group.delete() self.assertEqual(mock.call_count, 4) diff --git a/authentik/providers/scim/tests/test_membership.py b/authentik/providers/scim/tests/test_membership.py index a0506a7cd..f2bbc74c5 100644 --- a/authentik/providers/scim/tests/test_membership.py +++ b/authentik/providers/scim/tests/test_membership.py @@ -89,6 +89,7 @@ class SCIMMembershipTests(TestCase): self.assertJSONEqual( mocker.request_history[3].body, { + "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"], "emails": [], "active": True, "externalId": user.uid, @@ -99,7 +100,11 @@ class SCIMMembershipTests(TestCase): ) self.assertJSONEqual( mocker.request_history[5].body, - {"externalId": str(group.pk), "displayName": group.name}, + { + "schemas": ["urn:ietf:params:scim:schemas:core:2.0:Group"], + "externalId": str(group.pk), + "displayName": group.name, + }, ) with Mocker() as mocker: @@ -118,6 +123,7 @@ class SCIMMembershipTests(TestCase): self.assertJSONEqual( mocker.request_history[1].body, { + "schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"], "Operations": [ { "op": "add", @@ -125,7 +131,6 @@ class SCIMMembershipTests(TestCase): "value": [{"value": user_scim_id}], } ], - "schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"], }, ) @@ -174,6 +179,7 @@ class SCIMMembershipTests(TestCase): self.assertJSONEqual( mocker.request_history[3].body, { + "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"], "active": True, "displayName": "", "emails": [], @@ -184,7 +190,11 @@ class SCIMMembershipTests(TestCase): ) self.assertJSONEqual( mocker.request_history[5].body, - {"externalId": str(group.pk), "displayName": group.name}, + { + "schemas": ["urn:ietf:params:scim:schemas:core:2.0:Group"], + "externalId": str(group.pk), + "displayName": group.name, + }, ) with Mocker() as mocker: @@ -203,6 +213,7 @@ class SCIMMembershipTests(TestCase): self.assertJSONEqual( mocker.request_history[1].body, { + "schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"], "Operations": [ { "op": "add", @@ -210,7 +221,6 @@ class SCIMMembershipTests(TestCase): "value": [{"value": user_scim_id}], } ], - "schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"], }, ) @@ -230,6 +240,7 @@ class SCIMMembershipTests(TestCase): self.assertJSONEqual( mocker.request_history[1].body, { + "schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"], "Operations": [ { "op": "remove", @@ -237,6 +248,5 @@ class SCIMMembershipTests(TestCase): "value": [{"value": user_scim_id}], } ], - "schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"], }, ) diff --git a/authentik/providers/scim/tests/test_user.py b/authentik/providers/scim/tests/test_user.py index 842674b10..36377b925 100644 --- a/authentik/providers/scim/tests/test_user.py +++ b/authentik/providers/scim/tests/test_user.py @@ -66,6 +66,7 @@ class SCIMUserTests(TestCase): self.assertJSONEqual( mock.request_history[1].body, { + "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"], "active": True, "emails": [ { @@ -121,6 +122,7 @@ class SCIMUserTests(TestCase): self.assertEqual( body, { + "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"], "active": True, "emails": [ { @@ -173,6 +175,7 @@ class SCIMUserTests(TestCase): self.assertJSONEqual( mock.request_history[1].body, { + "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"], "active": True, "emails": [ { @@ -240,6 +243,7 @@ class SCIMUserTests(TestCase): self.assertJSONEqual( mock.request_history[1].body, { + "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"], "active": True, "emails": [ {