We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
SCIM exhausts all workers
**Describe the bug**

We do not have a SCIM provider configured but there are 8 workers constantly doing SCIM tasks and the number of entries in Redis continues to grow indefinitely (more than 200K right now).

**To Reproduce**
Steps to reproduce the behavior:

1. Have an LDAP source with at least 900 users and another 900 groups, with a total of 147k memberships.
2. Just wait for LDAP sync.
3. See how SCIM tasks take up all the workers despite not having a SCIM provider configured.

**Expected behavior**

Without a SCIM provider, there is no SCIM tasks to do.

**Logs**

All worker logs are similar to the following one:

```
{"event": "Task started", "level": "info", "logger": "authentik.root.celery", "pid": 62722, "task_id": "d8c04738-ba7f-4645-93fd-c5e634c0119c", "task_name": "scim_signal_direct", "timestamp": "2023-09-11T10:34:28.028322"}
{"event": "Task finished", "level": "info", "logger": "authentik.root.celery", "pid": 62722, "state": "SUCCESS", "task_id": "d8c04738-ba7f-4645-93fd-c5e634c0119c", "task_name": "scim_signal_direct", "timestamp": "2023-09-11T10:34:28.065772"}
{"event": "Task started", "level": "info", "logger": "authentik.root.celery", "pid": 62723, "task_id": "9fcf5591-1e26-4572-8f55-1dd50bc789fb", "task_name": "scim_signal_direct", "timestamp": "2023-09-11T10:34:28.472488"}
{"event": "Task finished", "level": "info", "logger": "authentik.root.celery", "pid": 62723, "state": "SUCCESS", "task_id": "9fcf5591-1e26-4572-8f55-1dd50bc789fb", "task_name": "scim_signal_direct", "timestamp": "2023-09-11T10:34:28.518844"}
{"event": "Task started", "level": "info", "logger": "authentik.root.celery", "pid": 62724, "task_id": "7aa43f29-11ba-44e4-9687-e3b002580e6b", "task_name": "scim_signal_direct", "timestamp": "2023-09-11T10:34:28.906288"}
{"event": "Task finished", "level": "info", "logger": "authentik.root.celery", "pid": 62724, "state": "SUCCESS", "task_id": "7aa43f29-11ba-44e4-9687-e3b002580e6b", "task_name": "scim_signal_direct", "timestamp": "2023-09-11T10:34:28.947772"}
{"event": "Task started", "level": "info", "logger": "authentik.root.celery", "pid": 62725, "task_id": "074a50e4-8454-4684-acff-eb46c5a25eff", "task_name": "scim_signal_direct", "timestamp": "2023-09-11T10:34:29.384486"}
{"event": "Task finished", "level": "info", "logger": "authentik.root.celery", "pid": 62725, "state": "SUCCESS", "task_id": "074a50e4-8454-4684-acff-eb46c5a25eff", "task_name": "scim_signal_direct", "timestamp": "2023-09-11T10:34:29.422690"}
{"event": "Task started", "level": "info", "logger": "authentik.root.celery", "pid": 62726, "task_id": "c155e461-1185-40a9-8018-685f399eb750", "task_name": "scim_signal_direct", "timestamp": "2023-09-11T10:34:29.841684"}
{"event": "Task finished", "level": "info", "logger": "authentik.root.celery", "pid": 62726, "state": "SUCCESS", "task_id": "c155e461-1185-40a9-8018-685f399eb750", "task_name": "scim_signal_direct", "timestamp": "2023-09-11T10:34:29.881108"}
{"event": "Task started", "level": "info", "logger": "authentik.root.celery", "pid": 62727, "task_id": "2ebd8a0e-83ca-4224-b14c-fdb4ad1e7c72", "task_name": "scim_signal_direct", "timestamp": "2023-09-11T10:34:30.313036"}
{"event": "Task finished", "level": "info", "logger": "authentik.root.celery", "pid": 62727, "state": "SUCCESS", "task_id": "2ebd8a0e-83ca-4224-b14c-fdb4ad1e7c72", "task_name": "scim_signal_direct", "timestamp": "2023-09-11T10:34:30.355698"}
{"event": "Task started", "level": "info", "logger": "authentik.root.celery", "pid": 62728, "task_id": "8c9a7cec-657d-49f5-a6a6-1e72a5f2d1c6", "task_name": "scim_signal_direct", "timestamp": "2023-09-11T10:34:30.793799"}
{"event": "Task finished", "level": "info", "logger": "authentik.root.celery", "pid": 62728, "state": "SUCCESS", "task_id": "8c9a7cec-657d-49f5-a6a6-1e72a5f2d1c6", "task_name": "scim_signal_direct", "timestamp": "2023-09-11T10:34:30.836449"}
{"event": "Task started", "level": "info", "logger": "authentik.root.celery", "pid": 62729, "task_id": "70fbfbfb-a63e-45df-bd99-fa6ece27181e", "task_name": "scim_signal_direct", "timestamp": "2023-09-11T10:34:31.210426"}
{"event": "Task finished", "level": "info", "logger": "authentik.root.celery", "pid": 62729, "state": "SUCCESS", "task_id": "70fbfbfb-a63e-45df-bd99-fa6ece27181e", "task_name": "scim_signal_direct", "timestamp": "2023-09-11T10:34:31.251003"}
{"event": "Task started", "level": "info", "logger": "authentik.root.celery", "pid": 62730, "task_id": "197ba0ec-424f-440d-9b2d-436cb34cb031", "task_name": "scim_signal_direct", "timestamp": "2023-09-11T10:34:31.684274"}
{"event": "Task finished", "level": "info", "logger": "authentik.root.celery", "pid": 62730, "state": "SUCCESS", "task_id": "197ba0ec-424f-440d-9b2d-436cb34cb031", "task_name": "scim_signal_direct", "timestamp": "2023-09-11T10:34:31.724073"}
{"event": "Task started", "level": "info", "logger": "authentik.root.celery", "pid": 62699, "task_id": "34e4f35a-8d6c-4a3a-96db-58fd30dc1878", "task_name": "scim_signal_direct", "timestamp": "2023-09-11T10:34:32.330238"}
{"event": "Task finished", "level": "info", "logger": "authentik.root.celery", "pid": 62699, "state": "SUCCESS", "task_id": "34e4f35a-8d6c-4a3a-96db-58fd30dc1878", "task_name": "scim_signal_direct", "timestamp": "2023-09-11T10:34:32.368228"}
{"event": "Task started", "level": "info", "logger": "authentik.root.celery", "pid": 62732, "task_id": "fd2ffb15-bf94-4684-b49d-011b61d1d459", "task_name": "scim_signal_direct", "timestamp": "2023-09-11T10:35:03.788787"}
{"event": "Task finished", "level": "info", "logger": "authentik.root.celery", "pid": 62732, "state": "SUCCESS", "task_id": "fd2ffb15-bf94-4684-b49d-011b61d1d459", "task_name": "scim_signal_direct", "timestamp": "2023-09-11T10:35:03.828492"}
{"event": "Task started", "level": "info", "logger": "authentik.root.celery", "pid": 62733, "task_id": "6b536317-decd-4fa9-a39c-083bdd1cf2ac", "task_name": "scim_signal_direct", "timestamp": "2023-09-11T10:35:08.961920"}
{"event": "Task finished", "level": "info", "logger": "authentik.root.celery", "pid": 62733, "state": "SUCCESS", "task_id": "6b536317-decd-4fa9-a39c-083bdd1cf2ac", "task_name": "scim_signal_direct", "timestamp": "2023-09-11T10:35:09.002660"}
{"event": "Task started", "level": "info", "logger": "authentik.root.celery", "pid": 62734, "task_id": "94fde81c-11cd-4811-8bb0-279f7b1b4fa8", "task_name": "scim_signal_direct", "timestamp": "2023-09-11T10:35:19.022284"}
{"event": "Task finished", "level": "info", "logger": "authentik.root.celery", "pid": 62734, "state": "SUCCESS", "task_id": "94fde81c-11cd-4811-8bb0-279f7b1b4fa8", "task_name": "scim_signal_direct", "timestamp": "2023-09-11T10:35:19.061598"}
```

**Version and Deployment (please complete the following information):**

-   authentik version: 2023.6.1
-   Deployment: helm

**Additional context**

Ask whatever you need.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `authentik/providers/scim/signals.py`
Content:
```
1 """SCIM provider signals"""
2 from django.db.models import Model
3 from django.db.models.signals import m2m_changed, post_save, pre_delete
4 from django.dispatch import receiver
5 from pydanticscim.responses import PatchOp
6 from structlog.stdlib import get_logger
7 
8 from authentik.core.models import Group, User
9 from authentik.lib.utils.reflection import class_to_path
10 from authentik.providers.scim.models import SCIMProvider
11 from authentik.providers.scim.tasks import scim_signal_direct, scim_signal_m2m, scim_sync
12 
13 LOGGER = get_logger()
14 
15 
16 @receiver(post_save, sender=SCIMProvider)
17 def post_save_provider(sender: type[Model], instance, created: bool, **_):
18     """Trigger sync when SCIM provider is saved"""
19     scim_sync.delay(instance.pk)
20 
21 
22 @receiver(post_save, sender=User)
23 @receiver(post_save, sender=Group)
24 def post_save_scim(sender: type[Model], instance: User | Group, created: bool, **_):
25     """Post save handler"""
26     scim_signal_direct.delay(class_to_path(instance.__class__), instance.pk, PatchOp.add.value)
27 
28 
29 @receiver(pre_delete, sender=User)
30 @receiver(pre_delete, sender=Group)
31 def pre_delete_scim(sender: type[Model], instance: User | Group, **_):
32     """Pre-delete handler"""
33     scim_signal_direct.delay(class_to_path(instance.__class__), instance.pk, PatchOp.remove.value)
34 
35 
36 @receiver(m2m_changed, sender=User.ak_groups.through)
37 def m2m_changed_scim(
38     sender: type[Model], instance, action: str, pk_set: set, reverse: bool, **kwargs
39 ):
40     """Sync group membership"""
41     if action not in ["post_add", "post_remove"]:
42         return
43     # reverse: instance is a Group, pk_set is a list of user pks
44     # non-reverse: instance is a User, pk_set is a list of groups
45     if reverse:
46         scim_signal_m2m.delay(str(instance.pk), action, list(pk_set))
47     else:
48         for group_pk in pk_set:
49             scim_signal_m2m.delay(group_pk, action, [instance.pk])
50
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/authentik/providers/scim/signals.py b/authentik/providers/scim/signals.py
--- a/authentik/providers/scim/signals.py
+++ b/authentik/providers/scim/signals.py
@@ -23,6 +23,8 @@
 @receiver(post_save, sender=Group)
 def post_save_scim(sender: type[Model], instance: User | Group, created: bool, **_):
     """Post save handler"""
+    if not SCIMProvider.objects.filter(backchannel_application__isnull=False).exists():
+        return
     scim_signal_direct.delay(class_to_path(instance.__class__), instance.pk, PatchOp.add.value)
 
 
@@ -30,6 +32,8 @@
 @receiver(pre_delete, sender=Group)
 def pre_delete_scim(sender: type[Model], instance: User | Group, **_):
     """Pre-delete handler"""
+    if not SCIMProvider.objects.filter(backchannel_application__isnull=False).exists():
+        return
     scim_signal_direct.delay(class_to_path(instance.__class__), instance.pk, PatchOp.remove.value)
 
 
@@ -40,6 +44,8 @@
     """Sync group membership"""
     if action not in ["post_add", "post_remove"]:
         return
+    if not SCIMProvider.objects.filter(backchannel_application__isnull=False).exists():
+        return
     # reverse: instance is a Group, pk_set is a list of user pks
     # non-reverse: instance is a User, pk_set is a list of groups
     if reverse:

{"golden_diff": "diff --git a/authentik/providers/scim/signals.py b/authentik/providers/scim/signals.py\n--- a/authentik/providers/scim/signals.py\n+++ b/authentik/providers/scim/signals.py\n@@ -23,6 +23,8 @@\n @receiver(post_save, sender=Group)\n def post_save_scim(sender: type[Model], instance: User | Group, created: bool, **_):\n     \"\"\"Post save handler\"\"\"\n+    if not SCIMProvider.objects.filter(backchannel_application__isnull=False).exists():\n+        return\n     scim_signal_direct.delay(class_to_path(instance.__class__), instance.pk, PatchOp.add.value)\n \n \n@@ -30,6 +32,8 @@\n @receiver(pre_delete, sender=Group)\n def pre_delete_scim(sender: type[Model], instance: User | Group, **_):\n     \"\"\"Pre-delete handler\"\"\"\n+    if not SCIMProvider.objects.filter(backchannel_application__isnull=False).exists():\n+        return\n     scim_signal_direct.delay(class_to_path(instance.__class__), instance.pk, PatchOp.remove.value)\n \n \n@@ -40,6 +44,8 @@\n     \"\"\"Sync group membership\"\"\"\n     if action not in [\"post_add\", \"post_remove\"]:\n         return\n+    if not SCIMProvider.objects.filter(backchannel_application__isnull=False).exists():\n+        return\n     # reverse: instance is a Group, pk_set is a list of user pks\n     # non-reverse: instance is a User, pk_set is a list of groups\n     if reverse:\n", "issue": "SCIM exhausts all workers\n**Describe the bug**\r\n\r\nWe do not have a SCIM provider configured but there are 8 workers constantly doing SCIM tasks and the number of entries in Redis continues to grow indefinitely (more than 200K right now).\r\n\r\n**To Reproduce**\r\nSteps to reproduce the behavior:\r\n\r\n1. Have an LDAP source with at least 900 users and another 900 groups, with a total of 147k memberships.\r\n2. Just wait for LDAP sync.\r\n3. See how SCIM tasks take up all the workers despite not having a SCIM provider configured.\r\n\r\n**Expected behavior**\r\n\r\nWithout a SCIM provider, there is no SCIM tasks to do.\r\n\r\n**Logs**\r\n\r\nAll worker logs are similar to the following one:\r\n\r\n```\r\n{\"event\": \"Task started\", \"level\": \"info\", \"logger\": \"authentik.root.celery\", \"pid\": 62722, \"task_id\": \"d8c04738-ba7f-4645-93fd-c5e634c0119c\", \"task_name\": \"scim_signal_direct\", \"timestamp\": \"2023-09-11T10:34:28.028322\"}\r\n{\"event\": \"Task finished\", \"level\": \"info\", \"logger\": \"authentik.root.celery\", \"pid\": 62722, \"state\": \"SUCCESS\", \"task_id\": \"d8c04738-ba7f-4645-93fd-c5e634c0119c\", \"task_name\": \"scim_signal_direct\", \"timestamp\": \"2023-09-11T10:34:28.065772\"}\r\n{\"event\": \"Task started\", \"level\": \"info\", \"logger\": \"authentik.root.celery\", \"pid\": 62723, \"task_id\": \"9fcf5591-1e26-4572-8f55-1dd50bc789fb\", \"task_name\": \"scim_signal_direct\", \"timestamp\": \"2023-09-11T10:34:28.472488\"}\r\n{\"event\": \"Task finished\", \"level\": \"info\", \"logger\": \"authentik.root.celery\", \"pid\": 62723, \"state\": \"SUCCESS\", \"task_id\": \"9fcf5591-1e26-4572-8f55-1dd50bc789fb\", \"task_name\": \"scim_signal_direct\", \"timestamp\": \"2023-09-11T10:34:28.518844\"}\r\n{\"event\": \"Task started\", \"level\": \"info\", \"logger\": \"authentik.root.celery\", \"pid\": 62724, \"task_id\": \"7aa43f29-11ba-44e4-9687-e3b002580e6b\", \"task_name\": \"scim_signal_direct\", \"timestamp\": \"2023-09-11T10:34:28.906288\"}\r\n{\"event\": \"Task finished\", \"level\": \"info\", \"logger\": \"authentik.root.celery\", \"pid\": 62724, \"state\": \"SUCCESS\", \"task_id\": \"7aa43f29-11ba-44e4-9687-e3b002580e6b\", \"task_name\": \"scim_signal_direct\", \"timestamp\": \"2023-09-11T10:34:28.947772\"}\r\n{\"event\": \"Task started\", \"level\": \"info\", \"logger\": \"authentik.root.celery\", \"pid\": 62725, \"task_id\": \"074a50e4-8454-4684-acff-eb46c5a25eff\", \"task_name\": \"scim_signal_direct\", \"timestamp\": \"2023-09-11T10:34:29.384486\"}\r\n{\"event\": \"Task finished\", \"level\": \"info\", \"logger\": \"authentik.root.celery\", \"pid\": 62725, \"state\": \"SUCCESS\", \"task_id\": \"074a50e4-8454-4684-acff-eb46c5a25eff\", \"task_name\": \"scim_signal_direct\", \"timestamp\": \"2023-09-11T10:34:29.422690\"}\r\n{\"event\": \"Task started\", \"level\": \"info\", \"logger\": \"authentik.root.celery\", \"pid\": 62726, \"task_id\": \"c155e461-1185-40a9-8018-685f399eb750\", \"task_name\": \"scim_signal_direct\", \"timestamp\": \"2023-09-11T10:34:29.841684\"}\r\n{\"event\": \"Task finished\", \"level\": \"info\", \"logger\": \"authentik.root.celery\", \"pid\": 62726, \"state\": \"SUCCESS\", \"task_id\": \"c155e461-1185-40a9-8018-685f399eb750\", \"task_name\": \"scim_signal_direct\", \"timestamp\": \"2023-09-11T10:34:29.881108\"}\r\n{\"event\": \"Task started\", \"level\": \"info\", \"logger\": \"authentik.root.celery\", \"pid\": 62727, \"task_id\": \"2ebd8a0e-83ca-4224-b14c-fdb4ad1e7c72\", \"task_name\": \"scim_signal_direct\", \"timestamp\": \"2023-09-11T10:34:30.313036\"}\r\n{\"event\": \"Task finished\", \"level\": \"info\", \"logger\": \"authentik.root.celery\", \"pid\": 62727, \"state\": \"SUCCESS\", \"task_id\": \"2ebd8a0e-83ca-4224-b14c-fdb4ad1e7c72\", \"task_name\": \"scim_signal_direct\", \"timestamp\": \"2023-09-11T10:34:30.355698\"}\r\n{\"event\": \"Task started\", \"level\": \"info\", \"logger\": \"authentik.root.celery\", \"pid\": 62728, \"task_id\": \"8c9a7cec-657d-49f5-a6a6-1e72a5f2d1c6\", \"task_name\": \"scim_signal_direct\", \"timestamp\": \"2023-09-11T10:34:30.793799\"}\r\n{\"event\": \"Task finished\", \"level\": \"info\", \"logger\": \"authentik.root.celery\", \"pid\": 62728, \"state\": \"SUCCESS\", \"task_id\": \"8c9a7cec-657d-49f5-a6a6-1e72a5f2d1c6\", \"task_name\": \"scim_signal_direct\", \"timestamp\": \"2023-09-11T10:34:30.836449\"}\r\n{\"event\": \"Task started\", \"level\": \"info\", \"logger\": \"authentik.root.celery\", \"pid\": 62729, \"task_id\": \"70fbfbfb-a63e-45df-bd99-fa6ece27181e\", \"task_name\": \"scim_signal_direct\", \"timestamp\": \"2023-09-11T10:34:31.210426\"}\r\n{\"event\": \"Task finished\", \"level\": \"info\", \"logger\": \"authentik.root.celery\", \"pid\": 62729, \"state\": \"SUCCESS\", \"task_id\": \"70fbfbfb-a63e-45df-bd99-fa6ece27181e\", \"task_name\": \"scim_signal_direct\", \"timestamp\": \"2023-09-11T10:34:31.251003\"}\r\n{\"event\": \"Task started\", \"level\": \"info\", \"logger\": \"authentik.root.celery\", \"pid\": 62730, \"task_id\": \"197ba0ec-424f-440d-9b2d-436cb34cb031\", \"task_name\": \"scim_signal_direct\", \"timestamp\": \"2023-09-11T10:34:31.684274\"}\r\n{\"event\": \"Task finished\", \"level\": \"info\", \"logger\": \"authentik.root.celery\", \"pid\": 62730, \"state\": \"SUCCESS\", \"task_id\": \"197ba0ec-424f-440d-9b2d-436cb34cb031\", \"task_name\": \"scim_signal_direct\", \"timestamp\": \"2023-09-11T10:34:31.724073\"}\r\n{\"event\": \"Task started\", \"level\": \"info\", \"logger\": \"authentik.root.celery\", \"pid\": 62699, \"task_id\": \"34e4f35a-8d6c-4a3a-96db-58fd30dc1878\", \"task_name\": \"scim_signal_direct\", \"timestamp\": \"2023-09-11T10:34:32.330238\"}\r\n{\"event\": \"Task finished\", \"level\": \"info\", \"logger\": \"authentik.root.celery\", \"pid\": 62699, \"state\": \"SUCCESS\", \"task_id\": \"34e4f35a-8d6c-4a3a-96db-58fd30dc1878\", \"task_name\": \"scim_signal_direct\", \"timestamp\": \"2023-09-11T10:34:32.368228\"}\r\n{\"event\": \"Task started\", \"level\": \"info\", \"logger\": \"authentik.root.celery\", \"pid\": 62732, \"task_id\": \"fd2ffb15-bf94-4684-b49d-011b61d1d459\", \"task_name\": \"scim_signal_direct\", \"timestamp\": \"2023-09-11T10:35:03.788787\"}\r\n{\"event\": \"Task finished\", \"level\": \"info\", \"logger\": \"authentik.root.celery\", \"pid\": 62732, \"state\": \"SUCCESS\", \"task_id\": \"fd2ffb15-bf94-4684-b49d-011b61d1d459\", \"task_name\": \"scim_signal_direct\", \"timestamp\": \"2023-09-11T10:35:03.828492\"}\r\n{\"event\": \"Task started\", \"level\": \"info\", \"logger\": \"authentik.root.celery\", \"pid\": 62733, \"task_id\": \"6b536317-decd-4fa9-a39c-083bdd1cf2ac\", \"task_name\": \"scim_signal_direct\", \"timestamp\": \"2023-09-11T10:35:08.961920\"}\r\n{\"event\": \"Task finished\", \"level\": \"info\", \"logger\": \"authentik.root.celery\", \"pid\": 62733, \"state\": \"SUCCESS\", \"task_id\": \"6b536317-decd-4fa9-a39c-083bdd1cf2ac\", \"task_name\": \"scim_signal_direct\", \"timestamp\": \"2023-09-11T10:35:09.002660\"}\r\n{\"event\": \"Task started\", \"level\": \"info\", \"logger\": \"authentik.root.celery\", \"pid\": 62734, \"task_id\": \"94fde81c-11cd-4811-8bb0-279f7b1b4fa8\", \"task_name\": \"scim_signal_direct\", \"timestamp\": \"2023-09-11T10:35:19.022284\"}\r\n{\"event\": \"Task finished\", \"level\": \"info\", \"logger\": \"authentik.root.celery\", \"pid\": 62734, \"state\": \"SUCCESS\", \"task_id\": \"94fde81c-11cd-4811-8bb0-279f7b1b4fa8\", \"task_name\": \"scim_signal_direct\", \"timestamp\": \"2023-09-11T10:35:19.061598\"}\r\n```\r\n\r\n**Version and Deployment (please complete the following information):**\r\n\r\n-   authentik version: 2023.6.1\r\n-   Deployment: helm\r\n\r\n**Additional context**\r\n\r\nAsk whatever you need.\r\n\n", "before_files": [{"content": "\"\"\"SCIM provider signals\"\"\"\nfrom django.db.models import Model\nfrom django.db.models.signals import m2m_changed, post_save, pre_delete\nfrom django.dispatch import receiver\nfrom pydanticscim.responses import PatchOp\nfrom structlog.stdlib import get_logger\n\nfrom authentik.core.models import Group, User\nfrom authentik.lib.utils.reflection import class_to_path\nfrom authentik.providers.scim.models import SCIMProvider\nfrom authentik.providers.scim.tasks import scim_signal_direct, scim_signal_m2m, scim_sync\n\nLOGGER = get_logger()\n\n\n@receiver(post_save, sender=SCIMProvider)\ndef post_save_provider(sender: type[Model], instance, created: bool, **_):\n    \"\"\"Trigger sync when SCIM provider is saved\"\"\"\n    scim_sync.delay(instance.pk)\n\n\n@receiver(post_save, sender=User)\n@receiver(post_save, sender=Group)\ndef post_save_scim(sender: type[Model], instance: User | Group, created: bool, **_):\n    \"\"\"Post save handler\"\"\"\n    scim_signal_direct.delay(class_to_path(instance.__class__), instance.pk, PatchOp.add.value)\n\n\n@receiver(pre_delete, sender=User)\n@receiver(pre_delete, sender=Group)\ndef pre_delete_scim(sender: type[Model], instance: User | Group, **_):\n    \"\"\"Pre-delete handler\"\"\"\n    scim_signal_direct.delay(class_to_path(instance.__class__), instance.pk, PatchOp.remove.value)\n\n\n@receiver(m2m_changed, sender=User.ak_groups.through)\ndef m2m_changed_scim(\n    sender: type[Model], instance, action: str, pk_set: set, reverse: bool, **kwargs\n):\n    \"\"\"Sync group membership\"\"\"\n    if action not in [\"post_add\", \"post_remove\"]:\n        return\n    # reverse: instance is a Group, pk_set is a list of user pks\n    # non-reverse: instance is a User, pk_set is a list of groups\n    if reverse:\n        scim_signal_m2m.delay(str(instance.pk), action, list(pk_set))\n    else:\n        for group_pk in pk_set:\n            scim_signal_m2m.delay(group_pk, action, [instance.pk])\n", "path": "authentik/providers/scim/signals.py"}], "after_files": [{"content": "\"\"\"SCIM provider signals\"\"\"\nfrom django.db.models import Model\nfrom django.db.models.signals import m2m_changed, post_save, pre_delete\nfrom django.dispatch import receiver\nfrom pydanticscim.responses import PatchOp\nfrom structlog.stdlib import get_logger\n\nfrom authentik.core.models import Group, User\nfrom authentik.lib.utils.reflection import class_to_path\nfrom authentik.providers.scim.models import SCIMProvider\nfrom authentik.providers.scim.tasks import scim_signal_direct, scim_signal_m2m, scim_sync\n\nLOGGER = get_logger()\n\n\n@receiver(post_save, sender=SCIMProvider)\ndef post_save_provider(sender: type[Model], instance, created: bool, **_):\n    \"\"\"Trigger sync when SCIM provider is saved\"\"\"\n    scim_sync.delay(instance.pk)\n\n\n@receiver(post_save, sender=User)\n@receiver(post_save, sender=Group)\ndef post_save_scim(sender: type[Model], instance: User | Group, created: bool, **_):\n    \"\"\"Post save handler\"\"\"\n    if not SCIMProvider.objects.filter(backchannel_application__isnull=False).exists():\n        return\n    scim_signal_direct.delay(class_to_path(instance.__class__), instance.pk, PatchOp.add.value)\n\n\n@receiver(pre_delete, sender=User)\n@receiver(pre_delete, sender=Group)\ndef pre_delete_scim(sender: type[Model], instance: User | Group, **_):\n    \"\"\"Pre-delete handler\"\"\"\n    if not SCIMProvider.objects.filter(backchannel_application__isnull=False).exists():\n        return\n    scim_signal_direct.delay(class_to_path(instance.__class__), instance.pk, PatchOp.remove.value)\n\n\n@receiver(m2m_changed, sender=User.ak_groups.through)\ndef m2m_changed_scim(\n    sender: type[Model], instance, action: str, pk_set: set, reverse: bool, **kwargs\n):\n    \"\"\"Sync group membership\"\"\"\n    if action not in [\"post_add\", \"post_remove\"]:\n        return\n    if not SCIMProvider.objects.filter(backchannel_application__isnull=False).exists():\n        return\n    # reverse: instance is a Group, pk_set is a list of user pks\n    # non-reverse: instance is a User, pk_set is a list of groups\n    if reverse:\n        scim_signal_m2m.delay(str(instance.pk), action, list(pk_set))\n    else:\n        for group_pk in pk_set:\n            scim_signal_m2m.delay(group_pk, action, [instance.pk])\n", "path": "authentik/providers/scim/signals.py"}]}