diff --git a/passbook/sources/ldap/migrations/0003_default_ldap_property_mappings.py b/passbook/sources/ldap/migrations/0003_default_ldap_property_mappings.py new file mode 100644 index 000000000..318952211 --- /dev/null +++ b/passbook/sources/ldap/migrations/0003_default_ldap_property_mappings.py @@ -0,0 +1,35 @@ +# Generated by Django 3.0.6 on 2020-05-23 19:30 + +from django.apps.registry import Apps +from django.db import migrations + + +def create_default_ad_property_mappings(apps: Apps, schema_editor): + LDAPPropertyMapping = apps.get_model("passbook_sources_ldap", "LDAPPropertyMapping") + mapping = { + "name": "{{ ldap.name }}", + "first_name": "{{ ldap.givenName }}", + "last_name": "{{ ldap.sn }}", + "username": "{{ ldap.sAMAccountName }}", + "email": "{{ ldap.mail }}", + } + db_alias = schema_editor.connection.alias + for object_field, expression in mapping.items(): + LDAPPropertyMapping.objects.using(db_alias).get_or_create( + expression=expression, + object_field=object_field, + defaults={ + "name": f"Autogenerated LDAP Mapping: {expression} -> {object_field}" + }, + ) + + +class Migration(migrations.Migration): + + dependencies = [ + ("passbook_sources_ldap", "0002_ldapsource_sync_users"), + ] + + operations = [ + migrations.RunPython(create_default_ad_property_mappings), + ] diff --git a/passbook/sources/ldap/tests.py b/passbook/sources/ldap/tests.py new file mode 100644 index 000000000..faa3f4177 --- /dev/null +++ b/passbook/sources/ldap/tests.py @@ -0,0 +1,75 @@ +"""LDAP Source tests""" +from unittest.mock import PropertyMock, patch + +from django.test import TestCase +from ldap3 import MOCK_SYNC, OFFLINE_AD_2012_R2, Connection, Server + +from passbook.core.models import User +from passbook.sources.ldap.connector import Connector +from passbook.sources.ldap.models import LDAPPropertyMapping, LDAPSource + + +def _build_mock_connection() -> Connection: + """Create mock connection""" + server = Server("my_fake_server", get_info=OFFLINE_AD_2012_R2) + _pass = "foo" # noqa # nosec + connection = Connection( + server, + user="cn=my_user,ou=test,o=lab", + password=_pass, + client_strategy=MOCK_SYNC, + ) + connection.strategy.add_entry( + "cn=user0,ou=test,o=lab", + { + "userPassword": "test0000", + "sAMAccountName": "user0_sn", + "revision": 0, + "objectSid": "unique-test0000", + "objectCategory": "Person", + }, + ) + connection.strategy.add_entry( + "cn=user1,ou=test,o=lab", + { + "userPassword": "test1111", + "sAMAccountName": "user1_sn", + "revision": 0, + "objectSid": "unique-test1111", + "objectCategory": "Person", + }, + ) + connection.strategy.add_entry( + "cn=user2,ou=test,o=lab", + { + "userPassword": "test2222", + "sAMAccountName": "user2_sn", + "revision": 0, + "objectSid": "unique-test2222", + "objectCategory": "Person", + }, + ) + connection.bind() + return connection + + +LDAP_CONNECTION_PATCH = PropertyMock(return_value=_build_mock_connection()) + + +class LDAPSourceTests(TestCase): + """LDAP Source tests""" + + def setUp(self): + self.source = LDAPSource.objects.create( + name="ldap", slug="ldap", base_dn="o=lab" + ) + self.source.property_mappings.set(LDAPPropertyMapping.objects.all()) + self.source.save() + + @patch("passbook.sources.ldap.models.LDAPSource.connection", LDAP_CONNECTION_PATCH) + def test_sync_users(self): + """Test user sync""" + connector = Connector(self.source) + connector.sync_users() + user = User.objects.filter(username="user2_sn") + self.assertTrue(user.exists())