524 lines
24 KiB
Python
524 lines
24 KiB
Python
"""LDAP Source tests"""
|
|
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
from django.db.models import Q
|
|
from django.test import TestCase
|
|
|
|
from authentik.blueprints.tests import apply_blueprint
|
|
from authentik.core.models import Group, User
|
|
from authentik.core.tests.utils import create_test_admin_user
|
|
from authentik.events.models import Event, EventAction, SystemTask
|
|
from authentik.events.system_tasks import TaskStatus
|
|
from authentik.lib.generators import generate_id, generate_key
|
|
from authentik.lib.sync.outgoing.exceptions import StopSync
|
|
from authentik.lib.utils.reflection import class_to_path
|
|
from authentik.sources.ldap.models import (
|
|
GroupLDAPSourceConnection,
|
|
LDAPSource,
|
|
LDAPSourcePropertyMapping,
|
|
UserLDAPSourceConnection,
|
|
)
|
|
from authentik.sources.ldap.sync.forward_delete_users import DELETE_CHUNK_SIZE
|
|
from authentik.sources.ldap.sync.groups import GroupLDAPSynchronizer
|
|
from authentik.sources.ldap.sync.membership import MembershipLDAPSynchronizer
|
|
from authentik.sources.ldap.sync.users import UserLDAPSynchronizer
|
|
from authentik.sources.ldap.tasks import ldap_sync, ldap_sync_all
|
|
from authentik.sources.ldap.tests.mock_ad import mock_ad_connection
|
|
from authentik.sources.ldap.tests.mock_freeipa import mock_freeipa_connection
|
|
from authentik.sources.ldap.tests.mock_slapd import (
|
|
group_in_slapd_cn,
|
|
group_in_slapd_uid,
|
|
mock_slapd_connection,
|
|
user_in_slapd_cn,
|
|
user_in_slapd_uid,
|
|
)
|
|
|
|
LDAP_PASSWORD = generate_key()
|
|
|
|
|
|
class LDAPSyncTests(TestCase):
|
|
"""LDAP Sync tests"""
|
|
|
|
@apply_blueprint("system/sources-ldap.yaml")
|
|
def setUp(self):
|
|
self.source: LDAPSource = LDAPSource.objects.create(
|
|
name="ldap",
|
|
slug="ldap",
|
|
base_dn="dc=goauthentik,dc=io",
|
|
additional_user_dn="ou=users",
|
|
additional_group_dn="ou=groups",
|
|
)
|
|
|
|
def test_sync_missing_page(self):
|
|
"""Test sync with missing page"""
|
|
connection = MagicMock(return_value=mock_ad_connection(LDAP_PASSWORD))
|
|
with patch("authentik.sources.ldap.models.LDAPSource.connection", connection):
|
|
ldap_sync.delay(str(self.source.pk), class_to_path(UserLDAPSynchronizer), "foo").get()
|
|
task = SystemTask.objects.filter(name="ldap_sync", uid="ldap:users:foo").first()
|
|
self.assertEqual(task.status, TaskStatus.ERROR)
|
|
|
|
def test_sync_error(self):
|
|
"""Test user sync"""
|
|
self.source.user_property_mappings.set(
|
|
LDAPSourcePropertyMapping.objects.filter(
|
|
Q(managed__startswith="goauthentik.io/sources/ldap/default")
|
|
| Q(managed__startswith="goauthentik.io/sources/ldap/ms")
|
|
)
|
|
)
|
|
mapping = LDAPSourcePropertyMapping.objects.create(
|
|
name="name",
|
|
expression="q",
|
|
)
|
|
self.source.user_property_mappings.set([mapping])
|
|
self.source.save()
|
|
connection = MagicMock(return_value=mock_ad_connection(LDAP_PASSWORD))
|
|
with patch("authentik.sources.ldap.models.LDAPSource.connection", connection):
|
|
user_sync = UserLDAPSynchronizer(self.source)
|
|
with self.assertRaises(StopSync):
|
|
user_sync.sync_full()
|
|
self.assertFalse(User.objects.filter(username="user0_sn").exists())
|
|
self.assertFalse(User.objects.filter(username="user1_sn").exists())
|
|
events = Event.objects.filter(
|
|
action=EventAction.CONFIGURATION_ERROR,
|
|
context__message="Failed to evaluate property mapping: 'name'",
|
|
context__mapping__pk=mapping.pk.hex,
|
|
)
|
|
self.assertTrue(events.exists())
|
|
|
|
def test_sync_mapping(self):
|
|
"""Test property mappings"""
|
|
none = LDAPSourcePropertyMapping.objects.create(
|
|
name=generate_id(), expression="return None"
|
|
)
|
|
byte_mapping = LDAPSourcePropertyMapping.objects.create(
|
|
name=generate_id(), expression="return b''"
|
|
)
|
|
self.source.user_property_mappings.set(
|
|
LDAPSourcePropertyMapping.objects.filter(
|
|
Q(managed__startswith="goauthentik.io/sources/ldap/default")
|
|
| Q(managed__startswith="goauthentik.io/sources/ldap/ms")
|
|
)
|
|
)
|
|
self.source.user_property_mappings.add(none, byte_mapping)
|
|
connection = MagicMock(return_value=mock_ad_connection(LDAP_PASSWORD))
|
|
|
|
# we basically just test that the mappings don't throw errors
|
|
with patch("authentik.sources.ldap.models.LDAPSource.connection", connection):
|
|
user_sync = UserLDAPSynchronizer(self.source)
|
|
user_sync.sync_full()
|
|
|
|
def test_sync_users_ad(self):
|
|
"""Test user sync"""
|
|
self.source.user_property_mappings.set(
|
|
LDAPSourcePropertyMapping.objects.filter(
|
|
Q(managed__startswith="goauthentik.io/sources/ldap/default")
|
|
| Q(managed__startswith="goauthentik.io/sources/ldap/ms")
|
|
)
|
|
)
|
|
connection = MagicMock(return_value=mock_ad_connection(LDAP_PASSWORD))
|
|
|
|
# Create the user beforehand so we can set attributes and check they aren't removed
|
|
user = User.objects.create(
|
|
username="user0_sn",
|
|
attributes={
|
|
"ldap_uniq": (
|
|
"S-117-6648368-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-"
|
|
"0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-"
|
|
"0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-"
|
|
"0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0"
|
|
),
|
|
"foo": "bar",
|
|
},
|
|
)
|
|
|
|
with patch("authentik.sources.ldap.models.LDAPSource.connection", connection):
|
|
user_sync = UserLDAPSynchronizer(self.source)
|
|
user_sync.sync_full()
|
|
user = User.objects.filter(username="user0_sn").first()
|
|
self.assertEqual(user.attributes["foo"], "bar")
|
|
self.assertFalse(user.is_active)
|
|
self.assertEqual(user.path, "goauthentik.io/sources/ldap/users/foo")
|
|
self.assertFalse(User.objects.filter(username="user1_sn").exists())
|
|
|
|
def test_sync_users_openldap(self):
|
|
"""Test user sync"""
|
|
self.source.object_uniqueness_field = "uid"
|
|
self.source.user_property_mappings.set(
|
|
LDAPSourcePropertyMapping.objects.filter(
|
|
Q(managed__startswith="goauthentik.io/sources/ldap/default")
|
|
| Q(managed__startswith="goauthentik.io/sources/ldap/openldap")
|
|
)
|
|
)
|
|
connection = MagicMock(return_value=mock_slapd_connection(LDAP_PASSWORD))
|
|
with patch("authentik.sources.ldap.models.LDAPSource.connection", connection):
|
|
user_sync = UserLDAPSynchronizer(self.source)
|
|
user_sync.sync_full()
|
|
self.assertTrue(User.objects.filter(username="user0_sn").exists())
|
|
self.assertFalse(User.objects.filter(username="user1_sn").exists())
|
|
|
|
def test_sync_users_freeipa_ish(self):
|
|
"""Test user sync (FreeIPA-ish), mainly testing vendor quirks"""
|
|
self.source.object_uniqueness_field = "uid"
|
|
self.source.user_property_mappings.set(
|
|
LDAPSourcePropertyMapping.objects.filter(
|
|
Q(managed__startswith="goauthentik.io/sources/ldap/default")
|
|
| Q(managed__startswith="goauthentik.io/sources/ldap/openldap")
|
|
)
|
|
)
|
|
connection = MagicMock(return_value=mock_freeipa_connection(LDAP_PASSWORD))
|
|
with patch("authentik.sources.ldap.models.LDAPSource.connection", connection):
|
|
user_sync = UserLDAPSynchronizer(self.source)
|
|
user_sync.sync_full()
|
|
self.assertTrue(User.objects.filter(username="user0_sn").exists())
|
|
self.assertFalse(User.objects.filter(username="user1_sn").exists())
|
|
self.assertFalse(User.objects.get(username="user-nsaccountlock").is_active)
|
|
|
|
def test_sync_groups_freeipa_memberOf(self):
|
|
"""Test group sync when membership is derived from memberOf user attribute"""
|
|
self.source.object_uniqueness_field = "uid"
|
|
self.source.group_object_filter = "(objectClass=groupOfNames)"
|
|
self.source.lookup_groups_from_user = True
|
|
self.source.group_membership_field = "memberOf"
|
|
self.source.user_property_mappings.set(
|
|
LDAPSourcePropertyMapping.objects.filter(
|
|
Q(managed__startswith="goauthentik.io/sources/ldap/default")
|
|
| Q(managed__startswith="goauthentik.io/sources/ldap/openldap")
|
|
)
|
|
)
|
|
self.source.group_property_mappings.set(
|
|
LDAPSourcePropertyMapping.objects.filter(
|
|
managed="goauthentik.io/sources/ldap/openldap-cn"
|
|
)
|
|
)
|
|
connection = MagicMock(return_value=mock_freeipa_connection(LDAP_PASSWORD))
|
|
with patch("authentik.sources.ldap.models.LDAPSource.connection", connection):
|
|
user_sync = UserLDAPSynchronizer(self.source)
|
|
user_sync.sync_full()
|
|
group_sync = GroupLDAPSynchronizer(self.source)
|
|
group_sync.sync_full()
|
|
membership_sync = MembershipLDAPSynchronizer(self.source)
|
|
membership_sync.sync_full()
|
|
|
|
self.assertTrue(
|
|
User.objects.filter(username="user4_sn").exists(), "User does not exist"
|
|
)
|
|
# Test if membership mapping based on memberOf works.
|
|
memberof_group = Group.objects.filter(name="reverse-lookup-group")
|
|
self.assertTrue(memberof_group.exists(), "Group does not exist")
|
|
self.assertTrue(
|
|
memberof_group.first().users.filter(username="user4_sn").exists(),
|
|
"User not a member of the group",
|
|
)
|
|
|
|
def test_sync_groups_ad(self):
|
|
"""Test group sync"""
|
|
self.source.user_property_mappings.set(
|
|
LDAPSourcePropertyMapping.objects.filter(
|
|
Q(managed__startswith="goauthentik.io/sources/ldap/default")
|
|
| Q(managed__startswith="goauthentik.io/sources/ldap/ms")
|
|
)
|
|
)
|
|
self.source.group_property_mappings.set(
|
|
LDAPSourcePropertyMapping.objects.filter(
|
|
managed="goauthentik.io/sources/ldap/default-name"
|
|
)
|
|
)
|
|
connection = MagicMock(return_value=mock_ad_connection(LDAP_PASSWORD))
|
|
with patch("authentik.sources.ldap.models.LDAPSource.connection", connection):
|
|
_user = create_test_admin_user()
|
|
parent_group = Group.objects.get(name=_user.username)
|
|
self.source.sync_parent_group = parent_group
|
|
self.source.save()
|
|
group_sync = GroupLDAPSynchronizer(self.source)
|
|
group_sync.sync_full()
|
|
membership_sync = MembershipLDAPSynchronizer(self.source)
|
|
membership_sync.sync_full()
|
|
group: Group = Group.objects.filter(name="test-group").first()
|
|
self.assertIsNotNone(group)
|
|
self.assertEqual(group.parent, parent_group)
|
|
|
|
def test_sync_groups_openldap(self):
|
|
"""Test group sync"""
|
|
self.source.object_uniqueness_field = "uid"
|
|
self.source.group_object_filter = "(objectClass=groupOfNames)"
|
|
self.source.user_property_mappings.set(
|
|
LDAPSourcePropertyMapping.objects.filter(
|
|
Q(managed__startswith="goauthentik.io/sources/ldap/default")
|
|
| Q(managed__startswith="goauthentik.io/sources/ldap/openldap")
|
|
)
|
|
)
|
|
self.source.group_property_mappings.set(
|
|
LDAPSourcePropertyMapping.objects.filter(
|
|
managed="goauthentik.io/sources/ldap/openldap-cn"
|
|
)
|
|
)
|
|
connection = MagicMock(return_value=mock_slapd_connection(LDAP_PASSWORD))
|
|
with patch("authentik.sources.ldap.models.LDAPSource.connection", connection):
|
|
self.source.save()
|
|
group_sync = GroupLDAPSynchronizer(self.source)
|
|
group_sync.sync_full()
|
|
membership_sync = MembershipLDAPSynchronizer(self.source)
|
|
membership_sync.sync_full()
|
|
group = Group.objects.filter(name="group1")
|
|
self.assertTrue(group.exists())
|
|
|
|
def test_sync_groups_openldap_posix_group(self):
|
|
"""Test posix group sync"""
|
|
self.source.object_uniqueness_field = "cn"
|
|
self.source.group_membership_field = "memberUid"
|
|
self.source.user_object_filter = "(objectClass=posixAccount)"
|
|
self.source.group_object_filter = "(objectClass=posixGroup)"
|
|
self.source.user_membership_attribute = "uid"
|
|
self.source.user_property_mappings.set(
|
|
[
|
|
*LDAPSourcePropertyMapping.objects.filter(
|
|
Q(managed__startswith="goauthentik.io/sources/ldap/default")
|
|
| Q(managed__startswith="goauthentik.io/sources/ldap/openldap")
|
|
).all(),
|
|
LDAPSourcePropertyMapping.objects.create(
|
|
name="name",
|
|
expression='return {"attributes": {"uid": list_flatten(ldap.get("uid"))}}',
|
|
),
|
|
]
|
|
)
|
|
self.source.group_property_mappings.set(
|
|
LDAPSourcePropertyMapping.objects.filter(
|
|
managed="goauthentik.io/sources/ldap/openldap-cn"
|
|
)
|
|
)
|
|
connection = MagicMock(return_value=mock_slapd_connection(LDAP_PASSWORD))
|
|
with patch("authentik.sources.ldap.models.LDAPSource.connection", connection):
|
|
self.source.save()
|
|
user_sync = UserLDAPSynchronizer(self.source)
|
|
user_sync.sync_full()
|
|
group_sync = GroupLDAPSynchronizer(self.source)
|
|
group_sync.sync_full()
|
|
membership_sync = MembershipLDAPSynchronizer(self.source)
|
|
membership_sync.sync_full()
|
|
# Test if membership mapping based on memberUid works.
|
|
posix_group = Group.objects.filter(name="group-posix").first()
|
|
self.assertTrue(posix_group.users.filter(name="user-posix").exists())
|
|
|
|
def test_sync_groups_openldap_posix_group_nonstandard_membership_attribute(self):
|
|
"""Test posix group sync"""
|
|
self.source.object_uniqueness_field = "cn"
|
|
self.source.group_membership_field = "memberUid"
|
|
self.source.user_object_filter = "(objectClass=posixAccount)"
|
|
self.source.group_object_filter = "(objectClass=posixGroup)"
|
|
self.source.user_membership_attribute = "cn"
|
|
self.source.user_property_mappings.set(
|
|
[
|
|
*LDAPSourcePropertyMapping.objects.filter(
|
|
Q(managed__startswith="goauthentik.io/sources/ldap/default")
|
|
| Q(managed__startswith="goauthentik.io/sources/ldap/openldap")
|
|
).all(),
|
|
LDAPSourcePropertyMapping.objects.create(
|
|
name="name",
|
|
expression='return {"attributes": {"cn": list_flatten(ldap.get("cn"))}}',
|
|
),
|
|
]
|
|
)
|
|
self.source.group_property_mappings.set(
|
|
LDAPSourcePropertyMapping.objects.filter(
|
|
managed="goauthentik.io/sources/ldap/openldap-cn"
|
|
)
|
|
)
|
|
connection = MagicMock(return_value=mock_slapd_connection(LDAP_PASSWORD))
|
|
with patch("authentik.sources.ldap.models.LDAPSource.connection", connection):
|
|
self.source.save()
|
|
user_sync = UserLDAPSynchronizer(self.source)
|
|
user_sync.sync_full()
|
|
group_sync = GroupLDAPSynchronizer(self.source)
|
|
group_sync.sync_full()
|
|
membership_sync = MembershipLDAPSynchronizer(self.source)
|
|
membership_sync.sync_full()
|
|
# Test if membership mapping based on memberUid works.
|
|
posix_group = Group.objects.filter(name="group-posix").first()
|
|
self.assertTrue(posix_group.users.filter(name="user-posix").exists())
|
|
|
|
def test_tasks_ad(self):
|
|
"""Test Scheduled tasks"""
|
|
self.source.user_property_mappings.set(
|
|
LDAPSourcePropertyMapping.objects.filter(
|
|
Q(managed__startswith="goauthentik.io/sources/ldap/default")
|
|
| Q(managed__startswith="goauthentik.io/sources/ldap/ms")
|
|
)
|
|
)
|
|
self.source.save()
|
|
connection = MagicMock(return_value=mock_ad_connection(LDAP_PASSWORD))
|
|
with patch("authentik.sources.ldap.models.LDAPSource.connection", connection):
|
|
ldap_sync_all.delay().get()
|
|
|
|
def test_tasks_openldap(self):
|
|
"""Test Scheduled tasks"""
|
|
self.source.object_uniqueness_field = "uid"
|
|
self.source.group_object_filter = "(objectClass=groupOfNames)"
|
|
self.source.user_property_mappings.set(
|
|
LDAPSourcePropertyMapping.objects.filter(
|
|
Q(managed__startswith="goauthentik.io/sources/ldap/default")
|
|
| Q(managed__startswith="goauthentik.io/sources/ldap/openldap")
|
|
)
|
|
)
|
|
self.source.save()
|
|
connection = MagicMock(return_value=mock_slapd_connection(LDAP_PASSWORD))
|
|
with patch("authentik.sources.ldap.models.LDAPSource.connection", connection):
|
|
ldap_sync_all.delay().get()
|
|
|
|
def test_user_deletion(self):
|
|
"""Test user deletion"""
|
|
user = User.objects.create_user(username="not-in-the-source")
|
|
UserLDAPSourceConnection.objects.create(
|
|
user=user, source=self.source, identifier="not-in-the-source"
|
|
)
|
|
self.source.object_uniqueness_field = "uid"
|
|
self.source.group_object_filter = "(objectClass=groupOfNames)"
|
|
self.source.delete_not_found_objects = True
|
|
self.source.save()
|
|
|
|
connection = MagicMock(return_value=mock_slapd_connection(LDAP_PASSWORD))
|
|
with patch("authentik.sources.ldap.models.LDAPSource.connection", connection):
|
|
ldap_sync_all.delay().get()
|
|
self.assertFalse(User.objects.filter(username="not-in-the-source").exists())
|
|
|
|
def test_user_deletion_still_in_source(self):
|
|
"""Test that user is not deleted if it's still in the source"""
|
|
username = user_in_slapd_cn
|
|
identifier = user_in_slapd_uid
|
|
user = User.objects.create_user(username=username)
|
|
UserLDAPSourceConnection.objects.create(
|
|
user=user, source=self.source, identifier=identifier
|
|
)
|
|
self.source.object_uniqueness_field = "uid"
|
|
self.source.group_object_filter = "(objectClass=groupOfNames)"
|
|
self.source.delete_not_found_objects = True
|
|
self.source.save()
|
|
|
|
connection = MagicMock(return_value=mock_slapd_connection(LDAP_PASSWORD))
|
|
with patch("authentik.sources.ldap.models.LDAPSource.connection", connection):
|
|
ldap_sync_all.delay().get()
|
|
self.assertTrue(User.objects.filter(username=username).exists())
|
|
|
|
def test_user_deletion_no_sync(self):
|
|
"""Test that user is not deleted if sync_users is False"""
|
|
user = User.objects.create_user(username="not-in-the-source")
|
|
UserLDAPSourceConnection.objects.create(
|
|
user=user, source=self.source, identifier="not-in-the-source"
|
|
)
|
|
self.source.object_uniqueness_field = "uid"
|
|
self.source.group_object_filter = "(objectClass=groupOfNames)"
|
|
self.source.delete_not_found_objects = True
|
|
self.source.sync_users = False
|
|
self.source.save()
|
|
|
|
connection = MagicMock(return_value=mock_slapd_connection(LDAP_PASSWORD))
|
|
with patch("authentik.sources.ldap.models.LDAPSource.connection", connection):
|
|
ldap_sync_all.delay().get()
|
|
self.assertTrue(User.objects.filter(username="not-in-the-source").exists())
|
|
|
|
def test_user_deletion_no_delete(self):
|
|
"""Test that user is not deleted if delete_not_found_objects is False"""
|
|
user = User.objects.create_user(username="not-in-the-source")
|
|
UserLDAPSourceConnection.objects.create(
|
|
user=user, source=self.source, identifier="not-in-the-source"
|
|
)
|
|
self.source.object_uniqueness_field = "uid"
|
|
self.source.group_object_filter = "(objectClass=groupOfNames)"
|
|
self.source.save()
|
|
|
|
connection = MagicMock(return_value=mock_slapd_connection(LDAP_PASSWORD))
|
|
with patch("authentik.sources.ldap.models.LDAPSource.connection", connection):
|
|
ldap_sync_all.delay().get()
|
|
self.assertTrue(User.objects.filter(username="not-in-the-source").exists())
|
|
|
|
def test_group_deletion(self):
|
|
"""Test group deletion"""
|
|
group = Group.objects.create(name="not-in-the-source")
|
|
GroupLDAPSourceConnection.objects.create(
|
|
group=group, source=self.source, identifier="not-in-the-source"
|
|
)
|
|
self.source.object_uniqueness_field = "uid"
|
|
self.source.group_object_filter = "(objectClass=groupOfNames)"
|
|
self.source.delete_not_found_objects = True
|
|
self.source.save()
|
|
|
|
connection = MagicMock(return_value=mock_slapd_connection(LDAP_PASSWORD))
|
|
with patch("authentik.sources.ldap.models.LDAPSource.connection", connection):
|
|
ldap_sync_all.delay().get()
|
|
self.assertFalse(Group.objects.filter(name="not-in-the-source").exists())
|
|
|
|
def test_group_deletion_still_in_source(self):
|
|
"""Test that group is not deleted if it's still in the source"""
|
|
groupname = group_in_slapd_cn
|
|
identifier = group_in_slapd_uid
|
|
group = Group.objects.create(name=groupname)
|
|
GroupLDAPSourceConnection.objects.create(
|
|
group=group, source=self.source, identifier=identifier
|
|
)
|
|
self.source.object_uniqueness_field = "uid"
|
|
self.source.group_object_filter = "(objectClass=groupOfNames)"
|
|
self.source.delete_not_found_objects = True
|
|
self.source.save()
|
|
|
|
connection = MagicMock(return_value=mock_slapd_connection(LDAP_PASSWORD))
|
|
with patch("authentik.sources.ldap.models.LDAPSource.connection", connection):
|
|
ldap_sync_all.delay().get()
|
|
self.assertTrue(Group.objects.filter(name=groupname).exists())
|
|
|
|
def test_group_deletion_no_sync(self):
|
|
"""Test that group is not deleted if sync_groups is False"""
|
|
group = Group.objects.create(name="not-in-the-source")
|
|
GroupLDAPSourceConnection.objects.create(
|
|
group=group, source=self.source, identifier="not-in-the-source"
|
|
)
|
|
self.source.object_uniqueness_field = "uid"
|
|
self.source.group_object_filter = "(objectClass=groupOfNames)"
|
|
self.source.delete_not_found_objects = True
|
|
self.source.sync_groups = False
|
|
self.source.save()
|
|
|
|
connection = MagicMock(return_value=mock_slapd_connection(LDAP_PASSWORD))
|
|
with patch("authentik.sources.ldap.models.LDAPSource.connection", connection):
|
|
ldap_sync_all.delay().get()
|
|
self.assertTrue(Group.objects.filter(name="not-in-the-source").exists())
|
|
|
|
def test_group_deletion_no_delete(self):
|
|
"""Test that group is not deleted if delete_not_found_objects is False"""
|
|
group = Group.objects.create(name="not-in-the-source")
|
|
GroupLDAPSourceConnection.objects.create(
|
|
group=group, source=self.source, identifier="not-in-the-source"
|
|
)
|
|
self.source.object_uniqueness_field = "uid"
|
|
self.source.group_object_filter = "(objectClass=groupOfNames)"
|
|
self.source.save()
|
|
|
|
connection = MagicMock(return_value=mock_slapd_connection(LDAP_PASSWORD))
|
|
with patch("authentik.sources.ldap.models.LDAPSource.connection", connection):
|
|
ldap_sync_all.delay().get()
|
|
self.assertTrue(Group.objects.filter(name="not-in-the-source").exists())
|
|
|
|
def test_batch_deletion(self):
|
|
"""Test batch deletion"""
|
|
BATCH_SIZE = DELETE_CHUNK_SIZE + 1
|
|
for i in range(BATCH_SIZE):
|
|
user = User.objects.create_user(username=f"not-in-the-source-{i}")
|
|
group = Group.objects.create(name=f"not-in-the-source-{i}")
|
|
group.users.add(user)
|
|
UserLDAPSourceConnection.objects.create(
|
|
user=user, source=self.source, identifier=f"not-in-the-source-{i}-user"
|
|
)
|
|
GroupLDAPSourceConnection.objects.create(
|
|
group=group, source=self.source, identifier=f"not-in-the-source-{i}-group"
|
|
)
|
|
self.source.object_uniqueness_field = "uid"
|
|
self.source.group_object_filter = "(objectClass=groupOfNames)"
|
|
self.source.delete_not_found_objects = True
|
|
self.source.save()
|
|
|
|
connection = MagicMock(return_value=mock_slapd_connection(LDAP_PASSWORD))
|
|
with patch("authentik.sources.ldap.models.LDAPSource.connection", connection):
|
|
ldap_sync_all.delay().get()
|
|
|
|
self.assertFalse(User.objects.filter(username__startswith="not-in-the-source").exists())
|
|
self.assertFalse(Group.objects.filter(name__startswith="not-in-the-source").exists())
|