authentik.sources.scim.tests.test_groups
Test SCIM Group
1"""Test SCIM Group""" 2 3from json import dumps 4from uuid import uuid4 5 6from django.urls import reverse 7from rest_framework.test import APITestCase 8 9from authentik.core.models import Group 10from authentik.core.tests.utils import create_test_user 11from authentik.events.models import Event, EventAction 12from authentik.lib.generators import generate_id 13from authentik.providers.scim.clients.schema import Group as SCIMGroupSchema 14from authentik.sources.scim.models import ( 15 SCIMSource, 16 SCIMSourceGroup, 17) 18from authentik.sources.scim.views.v2.base import SCIM_CONTENT_TYPE 19 20 21class TestSCIMGroups(APITestCase): 22 """Test SCIM Group view""" 23 24 def setUp(self) -> None: 25 self.source = SCIMSource.objects.create(name=generate_id(), slug=generate_id()) 26 27 def test_group_list(self): 28 """Test full group list""" 29 response = self.client.get( 30 reverse( 31 "authentik_sources_scim:v2-groups", 32 kwargs={ 33 "source_slug": self.source.slug, 34 }, 35 ), 36 HTTP_AUTHORIZATION=f"Bearer {self.source.token.key}", 37 ) 38 self.assertEqual(response.status_code, 200) 39 40 def test_group_list_single(self): 41 """Test full group list (single group)""" 42 group = Group.objects.create(name=generate_id()) 43 user = create_test_user() 44 group.users.add(user) 45 SCIMSourceGroup.objects.create( 46 source=self.source, 47 group=group, 48 id=str(uuid4()), 49 ) 50 response = self.client.get( 51 reverse( 52 "authentik_sources_scim:v2-groups", 53 kwargs={ 54 "source_slug": self.source.slug, 55 "group_id": str(group.pk), 56 }, 57 ), 58 HTTP_AUTHORIZATION=f"Bearer {self.source.token.key}", 59 ) 60 self.assertEqual(response.status_code, second=200) 61 SCIMGroupSchema.model_validate_json(response.content, strict=True) 62 63 def test_group_create(self): 64 """Test group create""" 65 ext_id = generate_id() 66 response = self.client.post( 67 reverse( 68 "authentik_sources_scim:v2-groups", 69 kwargs={ 70 "source_slug": self.source.slug, 71 }, 72 ), 73 data=dumps({"displayName": generate_id(), "externalId": ext_id}), 74 content_type=SCIM_CONTENT_TYPE, 75 HTTP_AUTHORIZATION=f"Bearer {self.source.token.key}", 76 ) 77 self.assertEqual(response.status_code, 201) 78 self.assertTrue( 79 SCIMSourceGroup.objects.filter(source=self.source, external_id=ext_id).exists() 80 ) 81 self.assertTrue( 82 Event.objects.filter( 83 action=EventAction.MODEL_CREATED, user__username=self.source.token.user.username 84 ).exists() 85 ) 86 87 def test_group_create_members(self): 88 """Test group create""" 89 user = create_test_user() 90 ext_id = generate_id() 91 name = generate_id() 92 response = self.client.post( 93 reverse( 94 "authentik_sources_scim:v2-groups", 95 kwargs={ 96 "source_slug": self.source.slug, 97 }, 98 ), 99 data=dumps( 100 { 101 "displayName": name, 102 "externalId": ext_id, 103 "members": [{"value": str(user.uuid)}], 104 } 105 ), 106 content_type=SCIM_CONTENT_TYPE, 107 HTTP_AUTHORIZATION=f"Bearer {self.source.token.key}", 108 ) 109 self.assertEqual(response.status_code, 201) 110 connection = SCIMSourceGroup.objects.filter(source=self.source, external_id=ext_id).first() 111 self.assertIsNotNone(connection) 112 self.assertTrue( 113 Event.objects.filter( 114 action=EventAction.MODEL_CREATED, user__username=self.source.token.user.username 115 ).exists() 116 ) 117 connection.refresh_from_db() 118 self.assertEqual( 119 connection.attributes, 120 { 121 "displayName": name, 122 "externalId": ext_id, 123 "members": [{"value": str(user.uuid)}], 124 }, 125 ) 126 127 def test_group_create_members_empty(self): 128 """Test group create""" 129 ext_id = generate_id() 130 response = self.client.post( 131 reverse( 132 "authentik_sources_scim:v2-groups", 133 kwargs={ 134 "source_slug": self.source.slug, 135 }, 136 ), 137 data=dumps({"displayName": generate_id(), "externalId": ext_id, "members": []}), 138 content_type=SCIM_CONTENT_TYPE, 139 HTTP_AUTHORIZATION=f"Bearer {self.source.token.key}", 140 ) 141 self.assertEqual(response.status_code, 201) 142 self.assertTrue( 143 SCIMSourceGroup.objects.filter(source=self.source, external_id=ext_id).exists() 144 ) 145 self.assertTrue( 146 Event.objects.filter( 147 action=EventAction.MODEL_CREATED, user__username=self.source.token.user.username 148 ).exists() 149 ) 150 151 def test_group_create_duplicate(self): 152 """Test group create (duplicate)""" 153 group = Group.objects.create(name=generate_id()) 154 existing = SCIMSourceGroup.objects.create( 155 source=self.source, group=group, external_id=uuid4() 156 ) 157 ext_id = generate_id() 158 response = self.client.post( 159 reverse( 160 "authentik_sources_scim:v2-groups", 161 kwargs={ 162 "source_slug": self.source.slug, 163 }, 164 ), 165 data=dumps( 166 {"displayName": generate_id(), "externalId": ext_id, "id": str(existing.group.pk)} 167 ), 168 content_type=SCIM_CONTENT_TYPE, 169 HTTP_AUTHORIZATION=f"Bearer {self.source.token.key}", 170 ) 171 self.assertEqual(response.status_code, 409) 172 self.assertJSONEqual( 173 response.content, 174 { 175 "detail": "Group with ID exists already.", 176 "schemas": ["urn:ietf:params:scim:api:messages:2.0:Error"], 177 "scimType": "uniqueness", 178 "status": 409, 179 }, 180 ) 181 182 def test_group_update(self): 183 """Test group update""" 184 group = Group.objects.create(name=generate_id()) 185 existing = SCIMSourceGroup.objects.create( 186 source=self.source, group=group, external_id=uuid4() 187 ) 188 ext_id = generate_id() 189 response = self.client.put( 190 reverse( 191 "authentik_sources_scim:v2-groups", 192 kwargs={"source_slug": self.source.slug, "group_id": group.pk}, 193 ), 194 data=dumps( 195 {"displayName": generate_id(), "externalId": ext_id, "id": str(existing.pk)} 196 ), 197 content_type=SCIM_CONTENT_TYPE, 198 HTTP_AUTHORIZATION=f"Bearer {self.source.token.key}", 199 ) 200 self.assertEqual(response.status_code, second=200) 201 202 def test_group_update_non_existent(self): 203 """Test group update""" 204 ext_id = generate_id() 205 response = self.client.put( 206 reverse( 207 "authentik_sources_scim:v2-groups", 208 kwargs={ 209 "source_slug": self.source.slug, 210 "group_id": str(uuid4()), 211 }, 212 ), 213 data=dumps({"displayName": generate_id(), "externalId": ext_id, "id": ""}), 214 content_type=SCIM_CONTENT_TYPE, 215 HTTP_AUTHORIZATION=f"Bearer {self.source.token.key}", 216 ) 217 self.assertEqual(response.status_code, second=404) 218 self.assertJSONEqual( 219 response.content, 220 { 221 "detail": "Group not found.", 222 "schemas": ["urn:ietf:params:scim:api:messages:2.0:Error"], 223 "status": 404, 224 }, 225 ) 226 227 def test_group_patch_modify(self): 228 """Test group patch""" 229 group = Group.objects.create(name=generate_id()) 230 connection = SCIMSourceGroup.objects.create( 231 source=self.source, 232 group=group, 233 external_id=uuid4(), 234 attributes={"displayName": group.name, "members": []}, 235 ) 236 response = self.client.patch( 237 reverse( 238 "authentik_sources_scim:v2-groups", 239 kwargs={"source_slug": self.source.slug, "group_id": group.pk}, 240 ), 241 data=dumps( 242 { 243 "Operations": [ 244 { 245 "op": "Add", 246 "value": {"externalId": "d85051cb-0557-4aa1-98ca-51eabcee4d40"}, 247 } 248 ] 249 } 250 ), 251 content_type=SCIM_CONTENT_TYPE, 252 HTTP_AUTHORIZATION=f"Bearer {self.source.token.key}", 253 ) 254 self.assertEqual(response.status_code, 200, response.content) 255 connection = SCIMSourceGroup.objects.filter(id="d85051cb-0557-4aa1-98ca-51eabcee4d40") 256 self.assertIsNotNone(connection) 257 258 def test_group_patch_member_add(self): 259 """Test group patch""" 260 user = create_test_user() 261 other_user = create_test_user() 262 group = Group.objects.create(name=generate_id()) 263 group.users.add(other_user) 264 connection = SCIMSourceGroup.objects.create( 265 source=self.source, 266 group=group, 267 external_id=uuid4(), 268 attributes={"displayName": group.name, "members": [{"value": str(other_user.uuid)}]}, 269 ) 270 response = self.client.patch( 271 reverse( 272 "authentik_sources_scim:v2-groups", 273 kwargs={"source_slug": self.source.slug, "group_id": group.pk}, 274 ), 275 data=dumps( 276 { 277 "Operations": [ 278 { 279 "op": "Add", 280 "path": "members", 281 "value": [{"value": str(user.uuid)}], 282 } 283 ] 284 } 285 ), 286 content_type=SCIM_CONTENT_TYPE, 287 HTTP_AUTHORIZATION=f"Bearer {self.source.token.key}", 288 ) 289 self.assertEqual(response.status_code, 200, response.content) 290 self.assertTrue(group.users.filter(pk=user.pk).exists()) 291 self.assertTrue(group.users.filter(pk=other_user.pk).exists()) 292 connection.refresh_from_db() 293 self.assertEqual( 294 connection.attributes, 295 { 296 "displayName": group.name, 297 "members": sorted( 298 [{"value": str(other_user.uuid)}, {"value": str(user.uuid)}], 299 key=lambda u: u["value"], 300 ), 301 }, 302 ) 303 304 def test_group_patch_member_remove(self): 305 """Test group patch""" 306 user = create_test_user() 307 308 group = Group.objects.create(name=generate_id()) 309 group.users.add(user) 310 connection = SCIMSourceGroup.objects.create( 311 source=self.source, 312 group=group, 313 external_id=uuid4(), 314 attributes={"displayName": group.name, "members": []}, 315 ) 316 response = self.client.patch( 317 reverse( 318 "authentik_sources_scim:v2-groups", 319 kwargs={"source_slug": self.source.slug, "group_id": group.pk}, 320 ), 321 data=dumps( 322 { 323 "Operations": [ 324 { 325 "op": "remove", 326 "path": "members", 327 "value": [{"value": str(user.uuid)}], 328 } 329 ] 330 } 331 ), 332 content_type=SCIM_CONTENT_TYPE, 333 HTTP_AUTHORIZATION=f"Bearer {self.source.token.key}", 334 ) 335 self.assertEqual(response.status_code, 200, response.content) 336 self.assertFalse(group.users.filter(pk=user.pk).exists()) 337 connection.refresh_from_db() 338 self.assertEqual( 339 connection.attributes, 340 { 341 "displayName": group.name, 342 "members": [], 343 }, 344 ) 345 346 def test_group_delete(self): 347 """Test group delete""" 348 group = Group.objects.create(name=generate_id()) 349 SCIMSourceGroup.objects.create(source=self.source, group=group, external_id=uuid4()) 350 response = self.client.delete( 351 reverse( 352 "authentik_sources_scim:v2-groups", 353 kwargs={"source_slug": self.source.slug, "group_id": group.pk}, 354 ), 355 content_type=SCIM_CONTENT_TYPE, 356 HTTP_AUTHORIZATION=f"Bearer {self.source.token.key}", 357 ) 358 self.assertEqual(response.status_code, second=204)
class
TestSCIMGroups(rest_framework.test.APITestCase):
22class TestSCIMGroups(APITestCase): 23 """Test SCIM Group view""" 24 25 def setUp(self) -> None: 26 self.source = SCIMSource.objects.create(name=generate_id(), slug=generate_id()) 27 28 def test_group_list(self): 29 """Test full group list""" 30 response = self.client.get( 31 reverse( 32 "authentik_sources_scim:v2-groups", 33 kwargs={ 34 "source_slug": self.source.slug, 35 }, 36 ), 37 HTTP_AUTHORIZATION=f"Bearer {self.source.token.key}", 38 ) 39 self.assertEqual(response.status_code, 200) 40 41 def test_group_list_single(self): 42 """Test full group list (single group)""" 43 group = Group.objects.create(name=generate_id()) 44 user = create_test_user() 45 group.users.add(user) 46 SCIMSourceGroup.objects.create( 47 source=self.source, 48 group=group, 49 id=str(uuid4()), 50 ) 51 response = self.client.get( 52 reverse( 53 "authentik_sources_scim:v2-groups", 54 kwargs={ 55 "source_slug": self.source.slug, 56 "group_id": str(group.pk), 57 }, 58 ), 59 HTTP_AUTHORIZATION=f"Bearer {self.source.token.key}", 60 ) 61 self.assertEqual(response.status_code, second=200) 62 SCIMGroupSchema.model_validate_json(response.content, strict=True) 63 64 def test_group_create(self): 65 """Test group create""" 66 ext_id = generate_id() 67 response = self.client.post( 68 reverse( 69 "authentik_sources_scim:v2-groups", 70 kwargs={ 71 "source_slug": self.source.slug, 72 }, 73 ), 74 data=dumps({"displayName": generate_id(), "externalId": ext_id}), 75 content_type=SCIM_CONTENT_TYPE, 76 HTTP_AUTHORIZATION=f"Bearer {self.source.token.key}", 77 ) 78 self.assertEqual(response.status_code, 201) 79 self.assertTrue( 80 SCIMSourceGroup.objects.filter(source=self.source, external_id=ext_id).exists() 81 ) 82 self.assertTrue( 83 Event.objects.filter( 84 action=EventAction.MODEL_CREATED, user__username=self.source.token.user.username 85 ).exists() 86 ) 87 88 def test_group_create_members(self): 89 """Test group create""" 90 user = create_test_user() 91 ext_id = generate_id() 92 name = generate_id() 93 response = self.client.post( 94 reverse( 95 "authentik_sources_scim:v2-groups", 96 kwargs={ 97 "source_slug": self.source.slug, 98 }, 99 ), 100 data=dumps( 101 { 102 "displayName": name, 103 "externalId": ext_id, 104 "members": [{"value": str(user.uuid)}], 105 } 106 ), 107 content_type=SCIM_CONTENT_TYPE, 108 HTTP_AUTHORIZATION=f"Bearer {self.source.token.key}", 109 ) 110 self.assertEqual(response.status_code, 201) 111 connection = SCIMSourceGroup.objects.filter(source=self.source, external_id=ext_id).first() 112 self.assertIsNotNone(connection) 113 self.assertTrue( 114 Event.objects.filter( 115 action=EventAction.MODEL_CREATED, user__username=self.source.token.user.username 116 ).exists() 117 ) 118 connection.refresh_from_db() 119 self.assertEqual( 120 connection.attributes, 121 { 122 "displayName": name, 123 "externalId": ext_id, 124 "members": [{"value": str(user.uuid)}], 125 }, 126 ) 127 128 def test_group_create_members_empty(self): 129 """Test group create""" 130 ext_id = generate_id() 131 response = self.client.post( 132 reverse( 133 "authentik_sources_scim:v2-groups", 134 kwargs={ 135 "source_slug": self.source.slug, 136 }, 137 ), 138 data=dumps({"displayName": generate_id(), "externalId": ext_id, "members": []}), 139 content_type=SCIM_CONTENT_TYPE, 140 HTTP_AUTHORIZATION=f"Bearer {self.source.token.key}", 141 ) 142 self.assertEqual(response.status_code, 201) 143 self.assertTrue( 144 SCIMSourceGroup.objects.filter(source=self.source, external_id=ext_id).exists() 145 ) 146 self.assertTrue( 147 Event.objects.filter( 148 action=EventAction.MODEL_CREATED, user__username=self.source.token.user.username 149 ).exists() 150 ) 151 152 def test_group_create_duplicate(self): 153 """Test group create (duplicate)""" 154 group = Group.objects.create(name=generate_id()) 155 existing = SCIMSourceGroup.objects.create( 156 source=self.source, group=group, external_id=uuid4() 157 ) 158 ext_id = generate_id() 159 response = self.client.post( 160 reverse( 161 "authentik_sources_scim:v2-groups", 162 kwargs={ 163 "source_slug": self.source.slug, 164 }, 165 ), 166 data=dumps( 167 {"displayName": generate_id(), "externalId": ext_id, "id": str(existing.group.pk)} 168 ), 169 content_type=SCIM_CONTENT_TYPE, 170 HTTP_AUTHORIZATION=f"Bearer {self.source.token.key}", 171 ) 172 self.assertEqual(response.status_code, 409) 173 self.assertJSONEqual( 174 response.content, 175 { 176 "detail": "Group with ID exists already.", 177 "schemas": ["urn:ietf:params:scim:api:messages:2.0:Error"], 178 "scimType": "uniqueness", 179 "status": 409, 180 }, 181 ) 182 183 def test_group_update(self): 184 """Test group update""" 185 group = Group.objects.create(name=generate_id()) 186 existing = SCIMSourceGroup.objects.create( 187 source=self.source, group=group, external_id=uuid4() 188 ) 189 ext_id = generate_id() 190 response = self.client.put( 191 reverse( 192 "authentik_sources_scim:v2-groups", 193 kwargs={"source_slug": self.source.slug, "group_id": group.pk}, 194 ), 195 data=dumps( 196 {"displayName": generate_id(), "externalId": ext_id, "id": str(existing.pk)} 197 ), 198 content_type=SCIM_CONTENT_TYPE, 199 HTTP_AUTHORIZATION=f"Bearer {self.source.token.key}", 200 ) 201 self.assertEqual(response.status_code, second=200) 202 203 def test_group_update_non_existent(self): 204 """Test group update""" 205 ext_id = generate_id() 206 response = self.client.put( 207 reverse( 208 "authentik_sources_scim:v2-groups", 209 kwargs={ 210 "source_slug": self.source.slug, 211 "group_id": str(uuid4()), 212 }, 213 ), 214 data=dumps({"displayName": generate_id(), "externalId": ext_id, "id": ""}), 215 content_type=SCIM_CONTENT_TYPE, 216 HTTP_AUTHORIZATION=f"Bearer {self.source.token.key}", 217 ) 218 self.assertEqual(response.status_code, second=404) 219 self.assertJSONEqual( 220 response.content, 221 { 222 "detail": "Group not found.", 223 "schemas": ["urn:ietf:params:scim:api:messages:2.0:Error"], 224 "status": 404, 225 }, 226 ) 227 228 def test_group_patch_modify(self): 229 """Test group patch""" 230 group = Group.objects.create(name=generate_id()) 231 connection = SCIMSourceGroup.objects.create( 232 source=self.source, 233 group=group, 234 external_id=uuid4(), 235 attributes={"displayName": group.name, "members": []}, 236 ) 237 response = self.client.patch( 238 reverse( 239 "authentik_sources_scim:v2-groups", 240 kwargs={"source_slug": self.source.slug, "group_id": group.pk}, 241 ), 242 data=dumps( 243 { 244 "Operations": [ 245 { 246 "op": "Add", 247 "value": {"externalId": "d85051cb-0557-4aa1-98ca-51eabcee4d40"}, 248 } 249 ] 250 } 251 ), 252 content_type=SCIM_CONTENT_TYPE, 253 HTTP_AUTHORIZATION=f"Bearer {self.source.token.key}", 254 ) 255 self.assertEqual(response.status_code, 200, response.content) 256 connection = SCIMSourceGroup.objects.filter(id="d85051cb-0557-4aa1-98ca-51eabcee4d40") 257 self.assertIsNotNone(connection) 258 259 def test_group_patch_member_add(self): 260 """Test group patch""" 261 user = create_test_user() 262 other_user = create_test_user() 263 group = Group.objects.create(name=generate_id()) 264 group.users.add(other_user) 265 connection = SCIMSourceGroup.objects.create( 266 source=self.source, 267 group=group, 268 external_id=uuid4(), 269 attributes={"displayName": group.name, "members": [{"value": str(other_user.uuid)}]}, 270 ) 271 response = self.client.patch( 272 reverse( 273 "authentik_sources_scim:v2-groups", 274 kwargs={"source_slug": self.source.slug, "group_id": group.pk}, 275 ), 276 data=dumps( 277 { 278 "Operations": [ 279 { 280 "op": "Add", 281 "path": "members", 282 "value": [{"value": str(user.uuid)}], 283 } 284 ] 285 } 286 ), 287 content_type=SCIM_CONTENT_TYPE, 288 HTTP_AUTHORIZATION=f"Bearer {self.source.token.key}", 289 ) 290 self.assertEqual(response.status_code, 200, response.content) 291 self.assertTrue(group.users.filter(pk=user.pk).exists()) 292 self.assertTrue(group.users.filter(pk=other_user.pk).exists()) 293 connection.refresh_from_db() 294 self.assertEqual( 295 connection.attributes, 296 { 297 "displayName": group.name, 298 "members": sorted( 299 [{"value": str(other_user.uuid)}, {"value": str(user.uuid)}], 300 key=lambda u: u["value"], 301 ), 302 }, 303 ) 304 305 def test_group_patch_member_remove(self): 306 """Test group patch""" 307 user = create_test_user() 308 309 group = Group.objects.create(name=generate_id()) 310 group.users.add(user) 311 connection = SCIMSourceGroup.objects.create( 312 source=self.source, 313 group=group, 314 external_id=uuid4(), 315 attributes={"displayName": group.name, "members": []}, 316 ) 317 response = self.client.patch( 318 reverse( 319 "authentik_sources_scim:v2-groups", 320 kwargs={"source_slug": self.source.slug, "group_id": group.pk}, 321 ), 322 data=dumps( 323 { 324 "Operations": [ 325 { 326 "op": "remove", 327 "path": "members", 328 "value": [{"value": str(user.uuid)}], 329 } 330 ] 331 } 332 ), 333 content_type=SCIM_CONTENT_TYPE, 334 HTTP_AUTHORIZATION=f"Bearer {self.source.token.key}", 335 ) 336 self.assertEqual(response.status_code, 200, response.content) 337 self.assertFalse(group.users.filter(pk=user.pk).exists()) 338 connection.refresh_from_db() 339 self.assertEqual( 340 connection.attributes, 341 { 342 "displayName": group.name, 343 "members": [], 344 }, 345 ) 346 347 def test_group_delete(self): 348 """Test group delete""" 349 group = Group.objects.create(name=generate_id()) 350 SCIMSourceGroup.objects.create(source=self.source, group=group, external_id=uuid4()) 351 response = self.client.delete( 352 reverse( 353 "authentik_sources_scim:v2-groups", 354 kwargs={"source_slug": self.source.slug, "group_id": group.pk}, 355 ), 356 content_type=SCIM_CONTENT_TYPE, 357 HTTP_AUTHORIZATION=f"Bearer {self.source.token.key}", 358 ) 359 self.assertEqual(response.status_code, second=204)
Test SCIM Group view
def
setUp(self) -> None:
25 def setUp(self) -> None: 26 self.source = SCIMSource.objects.create(name=generate_id(), slug=generate_id())
Hook method for setting up the test fixture before exercising it.
def
test_group_list(self):
28 def test_group_list(self): 29 """Test full group list""" 30 response = self.client.get( 31 reverse( 32 "authentik_sources_scim:v2-groups", 33 kwargs={ 34 "source_slug": self.source.slug, 35 }, 36 ), 37 HTTP_AUTHORIZATION=f"Bearer {self.source.token.key}", 38 ) 39 self.assertEqual(response.status_code, 200)
Test full group list
def
test_group_list_single(self):
41 def test_group_list_single(self): 42 """Test full group list (single group)""" 43 group = Group.objects.create(name=generate_id()) 44 user = create_test_user() 45 group.users.add(user) 46 SCIMSourceGroup.objects.create( 47 source=self.source, 48 group=group, 49 id=str(uuid4()), 50 ) 51 response = self.client.get( 52 reverse( 53 "authentik_sources_scim:v2-groups", 54 kwargs={ 55 "source_slug": self.source.slug, 56 "group_id": str(group.pk), 57 }, 58 ), 59 HTTP_AUTHORIZATION=f"Bearer {self.source.token.key}", 60 ) 61 self.assertEqual(response.status_code, second=200) 62 SCIMGroupSchema.model_validate_json(response.content, strict=True)
Test full group list (single group)
def
test_group_create(self):
64 def test_group_create(self): 65 """Test group create""" 66 ext_id = generate_id() 67 response = self.client.post( 68 reverse( 69 "authentik_sources_scim:v2-groups", 70 kwargs={ 71 "source_slug": self.source.slug, 72 }, 73 ), 74 data=dumps({"displayName": generate_id(), "externalId": ext_id}), 75 content_type=SCIM_CONTENT_TYPE, 76 HTTP_AUTHORIZATION=f"Bearer {self.source.token.key}", 77 ) 78 self.assertEqual(response.status_code, 201) 79 self.assertTrue( 80 SCIMSourceGroup.objects.filter(source=self.source, external_id=ext_id).exists() 81 ) 82 self.assertTrue( 83 Event.objects.filter( 84 action=EventAction.MODEL_CREATED, user__username=self.source.token.user.username 85 ).exists() 86 )
Test group create
def
test_group_create_members(self):
88 def test_group_create_members(self): 89 """Test group create""" 90 user = create_test_user() 91 ext_id = generate_id() 92 name = generate_id() 93 response = self.client.post( 94 reverse( 95 "authentik_sources_scim:v2-groups", 96 kwargs={ 97 "source_slug": self.source.slug, 98 }, 99 ), 100 data=dumps( 101 { 102 "displayName": name, 103 "externalId": ext_id, 104 "members": [{"value": str(user.uuid)}], 105 } 106 ), 107 content_type=SCIM_CONTENT_TYPE, 108 HTTP_AUTHORIZATION=f"Bearer {self.source.token.key}", 109 ) 110 self.assertEqual(response.status_code, 201) 111 connection = SCIMSourceGroup.objects.filter(source=self.source, external_id=ext_id).first() 112 self.assertIsNotNone(connection) 113 self.assertTrue( 114 Event.objects.filter( 115 action=EventAction.MODEL_CREATED, user__username=self.source.token.user.username 116 ).exists() 117 ) 118 connection.refresh_from_db() 119 self.assertEqual( 120 connection.attributes, 121 { 122 "displayName": name, 123 "externalId": ext_id, 124 "members": [{"value": str(user.uuid)}], 125 }, 126 )
Test group create
def
test_group_create_members_empty(self):
128 def test_group_create_members_empty(self): 129 """Test group create""" 130 ext_id = generate_id() 131 response = self.client.post( 132 reverse( 133 "authentik_sources_scim:v2-groups", 134 kwargs={ 135 "source_slug": self.source.slug, 136 }, 137 ), 138 data=dumps({"displayName": generate_id(), "externalId": ext_id, "members": []}), 139 content_type=SCIM_CONTENT_TYPE, 140 HTTP_AUTHORIZATION=f"Bearer {self.source.token.key}", 141 ) 142 self.assertEqual(response.status_code, 201) 143 self.assertTrue( 144 SCIMSourceGroup.objects.filter(source=self.source, external_id=ext_id).exists() 145 ) 146 self.assertTrue( 147 Event.objects.filter( 148 action=EventAction.MODEL_CREATED, user__username=self.source.token.user.username 149 ).exists() 150 )
Test group create
def
test_group_create_duplicate(self):
152 def test_group_create_duplicate(self): 153 """Test group create (duplicate)""" 154 group = Group.objects.create(name=generate_id()) 155 existing = SCIMSourceGroup.objects.create( 156 source=self.source, group=group, external_id=uuid4() 157 ) 158 ext_id = generate_id() 159 response = self.client.post( 160 reverse( 161 "authentik_sources_scim:v2-groups", 162 kwargs={ 163 "source_slug": self.source.slug, 164 }, 165 ), 166 data=dumps( 167 {"displayName": generate_id(), "externalId": ext_id, "id": str(existing.group.pk)} 168 ), 169 content_type=SCIM_CONTENT_TYPE, 170 HTTP_AUTHORIZATION=f"Bearer {self.source.token.key}", 171 ) 172 self.assertEqual(response.status_code, 409) 173 self.assertJSONEqual( 174 response.content, 175 { 176 "detail": "Group with ID exists already.", 177 "schemas": ["urn:ietf:params:scim:api:messages:2.0:Error"], 178 "scimType": "uniqueness", 179 "status": 409, 180 }, 181 )
Test group create (duplicate)
def
test_group_update(self):
183 def test_group_update(self): 184 """Test group update""" 185 group = Group.objects.create(name=generate_id()) 186 existing = SCIMSourceGroup.objects.create( 187 source=self.source, group=group, external_id=uuid4() 188 ) 189 ext_id = generate_id() 190 response = self.client.put( 191 reverse( 192 "authentik_sources_scim:v2-groups", 193 kwargs={"source_slug": self.source.slug, "group_id": group.pk}, 194 ), 195 data=dumps( 196 {"displayName": generate_id(), "externalId": ext_id, "id": str(existing.pk)} 197 ), 198 content_type=SCIM_CONTENT_TYPE, 199 HTTP_AUTHORIZATION=f"Bearer {self.source.token.key}", 200 ) 201 self.assertEqual(response.status_code, second=200)
Test group update
def
test_group_update_non_existent(self):
203 def test_group_update_non_existent(self): 204 """Test group update""" 205 ext_id = generate_id() 206 response = self.client.put( 207 reverse( 208 "authentik_sources_scim:v2-groups", 209 kwargs={ 210 "source_slug": self.source.slug, 211 "group_id": str(uuid4()), 212 }, 213 ), 214 data=dumps({"displayName": generate_id(), "externalId": ext_id, "id": ""}), 215 content_type=SCIM_CONTENT_TYPE, 216 HTTP_AUTHORIZATION=f"Bearer {self.source.token.key}", 217 ) 218 self.assertEqual(response.status_code, second=404) 219 self.assertJSONEqual( 220 response.content, 221 { 222 "detail": "Group not found.", 223 "schemas": ["urn:ietf:params:scim:api:messages:2.0:Error"], 224 "status": 404, 225 }, 226 )
Test group update
def
test_group_patch_modify(self):
228 def test_group_patch_modify(self): 229 """Test group patch""" 230 group = Group.objects.create(name=generate_id()) 231 connection = SCIMSourceGroup.objects.create( 232 source=self.source, 233 group=group, 234 external_id=uuid4(), 235 attributes={"displayName": group.name, "members": []}, 236 ) 237 response = self.client.patch( 238 reverse( 239 "authentik_sources_scim:v2-groups", 240 kwargs={"source_slug": self.source.slug, "group_id": group.pk}, 241 ), 242 data=dumps( 243 { 244 "Operations": [ 245 { 246 "op": "Add", 247 "value": {"externalId": "d85051cb-0557-4aa1-98ca-51eabcee4d40"}, 248 } 249 ] 250 } 251 ), 252 content_type=SCIM_CONTENT_TYPE, 253 HTTP_AUTHORIZATION=f"Bearer {self.source.token.key}", 254 ) 255 self.assertEqual(response.status_code, 200, response.content) 256 connection = SCIMSourceGroup.objects.filter(id="d85051cb-0557-4aa1-98ca-51eabcee4d40") 257 self.assertIsNotNone(connection)
Test group patch
def
test_group_patch_member_add(self):
259 def test_group_patch_member_add(self): 260 """Test group patch""" 261 user = create_test_user() 262 other_user = create_test_user() 263 group = Group.objects.create(name=generate_id()) 264 group.users.add(other_user) 265 connection = SCIMSourceGroup.objects.create( 266 source=self.source, 267 group=group, 268 external_id=uuid4(), 269 attributes={"displayName": group.name, "members": [{"value": str(other_user.uuid)}]}, 270 ) 271 response = self.client.patch( 272 reverse( 273 "authentik_sources_scim:v2-groups", 274 kwargs={"source_slug": self.source.slug, "group_id": group.pk}, 275 ), 276 data=dumps( 277 { 278 "Operations": [ 279 { 280 "op": "Add", 281 "path": "members", 282 "value": [{"value": str(user.uuid)}], 283 } 284 ] 285 } 286 ), 287 content_type=SCIM_CONTENT_TYPE, 288 HTTP_AUTHORIZATION=f"Bearer {self.source.token.key}", 289 ) 290 self.assertEqual(response.status_code, 200, response.content) 291 self.assertTrue(group.users.filter(pk=user.pk).exists()) 292 self.assertTrue(group.users.filter(pk=other_user.pk).exists()) 293 connection.refresh_from_db() 294 self.assertEqual( 295 connection.attributes, 296 { 297 "displayName": group.name, 298 "members": sorted( 299 [{"value": str(other_user.uuid)}, {"value": str(user.uuid)}], 300 key=lambda u: u["value"], 301 ), 302 }, 303 )
Test group patch
def
test_group_patch_member_remove(self):
305 def test_group_patch_member_remove(self): 306 """Test group patch""" 307 user = create_test_user() 308 309 group = Group.objects.create(name=generate_id()) 310 group.users.add(user) 311 connection = SCIMSourceGroup.objects.create( 312 source=self.source, 313 group=group, 314 external_id=uuid4(), 315 attributes={"displayName": group.name, "members": []}, 316 ) 317 response = self.client.patch( 318 reverse( 319 "authentik_sources_scim:v2-groups", 320 kwargs={"source_slug": self.source.slug, "group_id": group.pk}, 321 ), 322 data=dumps( 323 { 324 "Operations": [ 325 { 326 "op": "remove", 327 "path": "members", 328 "value": [{"value": str(user.uuid)}], 329 } 330 ] 331 } 332 ), 333 content_type=SCIM_CONTENT_TYPE, 334 HTTP_AUTHORIZATION=f"Bearer {self.source.token.key}", 335 ) 336 self.assertEqual(response.status_code, 200, response.content) 337 self.assertFalse(group.users.filter(pk=user.pk).exists()) 338 connection.refresh_from_db() 339 self.assertEqual( 340 connection.attributes, 341 { 342 "displayName": group.name, 343 "members": [], 344 }, 345 )
Test group patch
def
test_group_delete(self):
347 def test_group_delete(self): 348 """Test group delete""" 349 group = Group.objects.create(name=generate_id()) 350 SCIMSourceGroup.objects.create(source=self.source, group=group, external_id=uuid4()) 351 response = self.client.delete( 352 reverse( 353 "authentik_sources_scim:v2-groups", 354 kwargs={"source_slug": self.source.slug, "group_id": group.pk}, 355 ), 356 content_type=SCIM_CONTENT_TYPE, 357 HTTP_AUTHORIZATION=f"Bearer {self.source.token.key}", 358 ) 359 self.assertEqual(response.status_code, second=204)
Test group delete