authentik.sources.ldap.sync.forward_delete_users

 1from collections.abc import Generator
 2from itertools import batched
 3from uuid import uuid4
 4
 5from ldap3 import SUBTREE
 6
 7from authentik.core.models import User
 8from authentik.sources.ldap.models import UserLDAPSourceConnection
 9from authentik.sources.ldap.sync.base import BaseLDAPSynchronizer
10
11UPDATE_CHUNK_SIZE = 10_000
12DELETE_CHUNK_SIZE = 50
13
14
15class UserLDAPForwardDeletion(BaseLDAPSynchronizer):
16    """Delete LDAP Users from authentik"""
17
18    @staticmethod
19    def name() -> str:
20        return "user_deletions"
21
22    def get_objects(self, **kwargs) -> Generator:
23        if not self._source.sync_users or not self._source.delete_not_found_objects:
24            self._task.info("User syncing is disabled for this Source")
25            return iter(())
26
27        uuid = uuid4()
28        users = self._source.connection().extend.standard.paged_search(
29            search_base=self.base_dn_users,
30            search_filter=self._source.user_object_filter,
31            search_scope=SUBTREE,
32            attributes=[self._source.object_uniqueness_field],
33            generator=True,
34            **kwargs,
35        )
36        for batch in batched(users, UPDATE_CHUNK_SIZE, strict=False):
37            identifiers = []
38            for user in batch:
39                if not (attributes := self.get_attributes(user)):
40                    continue
41                if identifier := self.get_identifier(attributes):
42                    identifiers.append(identifier)
43            UserLDAPSourceConnection.objects.filter(identifier__in=identifiers).update(
44                validated_by=uuid
45            )
46
47        return batched(
48            UserLDAPSourceConnection.objects.filter(source=self._source)
49            .exclude(validated_by=uuid)
50            .values_list("user", flat=True)
51            .iterator(chunk_size=DELETE_CHUNK_SIZE),
52            DELETE_CHUNK_SIZE,
53            strict=False,
54        )
55
56    def sync(self, user_pks: tuple) -> int:
57        """Delete authentik users"""
58        if not self._source.sync_users or not self._source.delete_not_found_objects:
59            self._task.info("User syncing is disabled for this Source")
60            return -1
61        self._logger.debug("Deleting users", user_pks=user_pks)
62        _, deleted_per_type = User.objects.filter(pk__in=user_pks).delete()
63        return deleted_per_type.get(User._meta.label, 0)
UPDATE_CHUNK_SIZE = 10000
DELETE_CHUNK_SIZE = 50
class UserLDAPForwardDeletion(authentik.sources.ldap.sync.base.BaseLDAPSynchronizer):
16class UserLDAPForwardDeletion(BaseLDAPSynchronizer):
17    """Delete LDAP Users from authentik"""
18
19    @staticmethod
20    def name() -> str:
21        return "user_deletions"
22
23    def get_objects(self, **kwargs) -> Generator:
24        if not self._source.sync_users or not self._source.delete_not_found_objects:
25            self._task.info("User syncing is disabled for this Source")
26            return iter(())
27
28        uuid = uuid4()
29        users = self._source.connection().extend.standard.paged_search(
30            search_base=self.base_dn_users,
31            search_filter=self._source.user_object_filter,
32            search_scope=SUBTREE,
33            attributes=[self._source.object_uniqueness_field],
34            generator=True,
35            **kwargs,
36        )
37        for batch in batched(users, UPDATE_CHUNK_SIZE, strict=False):
38            identifiers = []
39            for user in batch:
40                if not (attributes := self.get_attributes(user)):
41                    continue
42                if identifier := self.get_identifier(attributes):
43                    identifiers.append(identifier)
44            UserLDAPSourceConnection.objects.filter(identifier__in=identifiers).update(
45                validated_by=uuid
46            )
47
48        return batched(
49            UserLDAPSourceConnection.objects.filter(source=self._source)
50            .exclude(validated_by=uuid)
51            .values_list("user", flat=True)
52            .iterator(chunk_size=DELETE_CHUNK_SIZE),
53            DELETE_CHUNK_SIZE,
54            strict=False,
55        )
56
57    def sync(self, user_pks: tuple) -> int:
58        """Delete authentik users"""
59        if not self._source.sync_users or not self._source.delete_not_found_objects:
60            self._task.info("User syncing is disabled for this Source")
61            return -1
62        self._logger.debug("Deleting users", user_pks=user_pks)
63        _, deleted_per_type = User.objects.filter(pk__in=user_pks).delete()
64        return deleted_per_type.get(User._meta.label, 0)

Delete LDAP Users from authentik

@staticmethod
def name() -> str:
19    @staticmethod
20    def name() -> str:
21        return "user_deletions"

UI name for the type of object this class synchronizes

def get_objects(self, **kwargs) -> Generator:
23    def get_objects(self, **kwargs) -> Generator:
24        if not self._source.sync_users or not self._source.delete_not_found_objects:
25            self._task.info("User syncing is disabled for this Source")
26            return iter(())
27
28        uuid = uuid4()
29        users = self._source.connection().extend.standard.paged_search(
30            search_base=self.base_dn_users,
31            search_filter=self._source.user_object_filter,
32            search_scope=SUBTREE,
33            attributes=[self._source.object_uniqueness_field],
34            generator=True,
35            **kwargs,
36        )
37        for batch in batched(users, UPDATE_CHUNK_SIZE, strict=False):
38            identifiers = []
39            for user in batch:
40                if not (attributes := self.get_attributes(user)):
41                    continue
42                if identifier := self.get_identifier(attributes):
43                    identifiers.append(identifier)
44            UserLDAPSourceConnection.objects.filter(identifier__in=identifiers).update(
45                validated_by=uuid
46            )
47
48        return batched(
49            UserLDAPSourceConnection.objects.filter(source=self._source)
50            .exclude(validated_by=uuid)
51            .values_list("user", flat=True)
52            .iterator(chunk_size=DELETE_CHUNK_SIZE),
53            DELETE_CHUNK_SIZE,
54            strict=False,
55        )

Get objects from LDAP, implemented in subclass

def sync(self, user_pks: tuple) -> int:
57    def sync(self, user_pks: tuple) -> int:
58        """Delete authentik users"""
59        if not self._source.sync_users or not self._source.delete_not_found_objects:
60            self._task.info("User syncing is disabled for this Source")
61            return -1
62        self._logger.debug("Deleting users", user_pks=user_pks)
63        _, deleted_per_type = User.objects.filter(pk__in=user_pks).delete()
64        return deleted_per_type.get(User._meta.label, 0)

Delete authentik users