-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
sources/ldap: add forward deletion option #14718
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
25f4eb7
sources/ldap: add forward deletion option
gergosimonyi b85ddc8
Merge branch 'main' into sources/ldap/add-forward-deletion-option
gergosimonyi 5bba6da
remove unnecessary `blank=True`
gergosimonyi 3f8a06b
clarify `validated_by` `help_text`
gergosimonyi 839d7e9
add indices to `validated_by`
gergosimonyi 3e3b733
factor out `get_identifier` everywhere and `get_attributes`
gergosimonyi 00f9c11
add tests for known good user and group
gergosimonyi 86b7481
fixup! add tests for known good user and group
gergosimonyi 825da1b
fixup! add tests for known good user and group
gergosimonyi File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
48 changes: 48 additions & 0 deletions
48
authentik/sources/ldap/migrations/0009_groupldapsourceconnection_validated_by_and_more.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
# Generated by Django 5.1.9 on 2025-05-28 08:15 | ||
|
||
from django.db import migrations, models | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
dependencies = [ | ||
("authentik_core", "0048_delete_oldauthenticatedsession_content_type"), | ||
("authentik_sources_ldap", "0008_groupldapsourceconnection_userldapsourceconnection"), | ||
] | ||
|
||
operations = [ | ||
migrations.AddField( | ||
model_name="groupldapsourceconnection", | ||
name="validated_by", | ||
field=models.UUIDField( | ||
blank=True, | ||
help_text="Unique ID used while checking if this object still exists in the directory.", | ||
null=True, | ||
), | ||
), | ||
migrations.AddField( | ||
model_name="ldapsource", | ||
name="delete_not_found_objects", | ||
field=models.BooleanField( | ||
default=False, | ||
help_text="Delete authentik users and groups which were previously supplied by this source, but are now missing from it.", | ||
), | ||
), | ||
migrations.AddField( | ||
model_name="userldapsourceconnection", | ||
name="validated_by", | ||
field=models.UUIDField( | ||
blank=True, | ||
help_text="Unique ID used while checking if this object still exists in the directory.", | ||
null=True, | ||
), | ||
), | ||
migrations.AddIndex( | ||
model_name="groupldapsourceconnection", | ||
index=models.Index(fields=["validated_by"], name="authentik_s_validat_b70447_idx"), | ||
), | ||
migrations.AddIndex( | ||
model_name="userldapsourceconnection", | ||
index=models.Index(fields=["validated_by"], name="authentik_s_validat_ff2ebc_idx"), | ||
), | ||
] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
from collections.abc import Generator | ||
from itertools import batched | ||
from uuid import uuid4 | ||
|
||
from ldap3 import SUBTREE | ||
|
||
from authentik.core.models import Group | ||
from authentik.sources.ldap.models import GroupLDAPSourceConnection | ||
from authentik.sources.ldap.sync.base import BaseLDAPSynchronizer | ||
from authentik.sources.ldap.sync.forward_delete_users import DELETE_CHUNK_SIZE, UPDATE_CHUNK_SIZE | ||
|
||
|
||
class GroupLDAPForwardDeletion(BaseLDAPSynchronizer): | ||
"""Delete LDAP Groups from authentik""" | ||
|
||
@staticmethod | ||
def name() -> str: | ||
return "group_deletions" | ||
|
||
def get_objects(self, **kwargs) -> Generator: | ||
if not self._source.sync_groups or not self._source.delete_not_found_objects: | ||
self.message("Group syncing is disabled for this Source") | ||
return iter(()) | ||
|
||
uuid = uuid4() | ||
groups = self._source.connection().extend.standard.paged_search( | ||
search_base=self.base_dn_groups, | ||
search_filter=self._source.group_object_filter, | ||
search_scope=SUBTREE, | ||
attributes=[self._source.object_uniqueness_field], | ||
generator=True, | ||
**kwargs, | ||
) | ||
for batch in batched(groups, UPDATE_CHUNK_SIZE, strict=False): | ||
identifiers = [] | ||
for group in batch: | ||
if not (attributes := self.get_attributes(group)): | ||
continue | ||
if identifier := self.get_identifier(attributes): | ||
identifiers.append(identifier) | ||
GroupLDAPSourceConnection.objects.filter(identifier__in=identifiers).update( | ||
validated_by=uuid | ||
) | ||
|
||
return batched( | ||
GroupLDAPSourceConnection.objects.filter(source=self._source) | ||
.exclude(validated_by=uuid) | ||
.values_list("group", flat=True) | ||
.iterator(chunk_size=DELETE_CHUNK_SIZE), | ||
DELETE_CHUNK_SIZE, | ||
strict=False, | ||
) | ||
|
||
def sync(self, group_pks: tuple) -> int: | ||
"""Delete authentik groups""" | ||
if not self._source.sync_groups or not self._source.delete_not_found_objects: | ||
self.message("Group syncing is disabled for this Source") | ||
return -1 | ||
self._logger.debug("Deleting groups", group_pks=group_pks) | ||
_, deleted_per_type = Group.objects.filter(pk__in=group_pks).delete() | ||
return deleted_per_type.get(Group._meta.label, 0) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
from collections.abc import Generator | ||
from itertools import batched | ||
from uuid import uuid4 | ||
|
||
from ldap3 import SUBTREE | ||
|
||
from authentik.core.models import User | ||
from authentik.sources.ldap.models import UserLDAPSourceConnection | ||
from authentik.sources.ldap.sync.base import BaseLDAPSynchronizer | ||
|
||
UPDATE_CHUNK_SIZE = 10_000 | ||
DELETE_CHUNK_SIZE = 50 | ||
|
||
|
||
class UserLDAPForwardDeletion(BaseLDAPSynchronizer): | ||
"""Delete LDAP Users from authentik""" | ||
|
||
@staticmethod | ||
def name() -> str: | ||
return "user_deletions" | ||
|
||
def get_objects(self, **kwargs) -> Generator: | ||
if not self._source.sync_users or not self._source.delete_not_found_objects: | ||
self.message("User syncing is disabled for this Source") | ||
return iter(()) | ||
|
||
uuid = uuid4() | ||
users = self._source.connection().extend.standard.paged_search( | ||
search_base=self.base_dn_users, | ||
search_filter=self._source.user_object_filter, | ||
search_scope=SUBTREE, | ||
attributes=[self._source.object_uniqueness_field], | ||
generator=True, | ||
**kwargs, | ||
) | ||
for batch in batched(users, UPDATE_CHUNK_SIZE, strict=False): | ||
identifiers = [] | ||
for user in batch: | ||
if not (attributes := self.get_attributes(user)): | ||
continue | ||
if identifier := self.get_identifier(attributes): | ||
identifiers.append(identifier) | ||
UserLDAPSourceConnection.objects.filter(identifier__in=identifiers).update( | ||
validated_by=uuid | ||
) | ||
|
||
return batched( | ||
UserLDAPSourceConnection.objects.filter(source=self._source) | ||
.exclude(validated_by=uuid) | ||
.values_list("user", flat=True) | ||
.iterator(chunk_size=DELETE_CHUNK_SIZE), | ||
DELETE_CHUNK_SIZE, | ||
strict=False, | ||
) | ||
|
||
def sync(self, user_pks: tuple) -> int: | ||
"""Delete authentik users""" | ||
if not self._source.sync_users or not self._source.delete_not_found_objects: | ||
self.message("User syncing is disabled for this Source") | ||
return -1 | ||
self._logger.debug("Deleting users", user_pks=user_pks) | ||
_, deleted_per_type = User.objects.filter(pk__in=user_pks).delete() | ||
return deleted_per_type.get(User._meta.label, 0) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.