authentik.sources.ldap.sync.users
Sync LDAP Users into authentik
1"""Sync LDAP Users into authentik""" 2 3from collections.abc import Generator 4 5from django.core.exceptions import FieldError 6from django.db.utils import IntegrityError 7from ldap3 import ALL_ATTRIBUTES, ALL_OPERATIONAL_ATTRIBUTES, SUBTREE 8 9from authentik.core.expression.exceptions import ( 10 PropertyMappingExpressionException, 11 SkipObjectException, 12) 13from authentik.core.models import User 14from authentik.core.sources.mapper import SourceMapper 15from authentik.events.models import Event, EventAction 16from authentik.lib.sync.outgoing.exceptions import StopSync 17from authentik.sources.ldap.models import ( 18 LDAP_UNIQUENESS, 19 LDAPSource, 20 UserLDAPSourceConnection, 21 flatten, 22) 23from authentik.sources.ldap.sync.base import BaseLDAPSynchronizer 24from authentik.sources.ldap.sync.vendor.freeipa import FreeIPA 25from authentik.sources.ldap.sync.vendor.ms_ad import MicrosoftActiveDirectory 26from authentik.tasks.models import Task 27 28 29class UserLDAPSynchronizer(BaseLDAPSynchronizer): 30 """Sync LDAP Users into authentik""" 31 32 def __init__(self, source: LDAPSource, task: Task): 33 super().__init__(source, task) 34 self.mapper = SourceMapper(source) 35 self.manager = self.mapper.get_manager(User, ["ldap", "dn"]) 36 37 @staticmethod 38 def name() -> str: 39 return "users" 40 41 def get_objects(self, **kwargs) -> Generator: 42 if not self._source.sync_users: 43 self._task.info("User syncing is disabled for this Source") 44 return iter(()) 45 return self.search_paginator( 46 search_base=self.base_dn_users, 47 search_filter=self._source.user_object_filter, 48 search_scope=SUBTREE, 49 attributes=[ 50 ALL_ATTRIBUTES, 51 ALL_OPERATIONAL_ATTRIBUTES, 52 self._source.object_uniqueness_field, 53 ], 54 **kwargs, 55 ) 56 57 def sync(self, page_data: list) -> int: 58 """Iterate over all LDAP Users and create authentik_core.User instances""" 59 if not self._source.sync_users: 60 self._task.info("User syncing is disabled for this Source") 61 return -1 62 user_count = 0 63 for user in page_data: 64 if (attributes := self.get_attributes(user)) is None: 65 continue 66 user_dn = flatten(user.get("entryDN", user.get("dn"))) 67 if not (uniq := self.get_identifier(attributes)): 68 self._task.info( 69 f"Uniqueness field not found/not set in attributes: '{user_dn}'", 70 attributes=list(attributes.keys()), 71 dn=user_dn, 72 ) 73 continue 74 try: 75 defaults = { 76 k: flatten(v) 77 for k, v in self.mapper.build_object_properties( 78 object_type=User, 79 manager=self.manager, 80 user=None, 81 request=None, 82 dn=user_dn, 83 ldap=attributes, 84 ).items() 85 } 86 self._logger.debug("Writing user with attributes", **defaults) 87 if "username" not in defaults: 88 raise IntegrityError("Username was not set by propertymappings") 89 ak_user, created = User.update_or_create_attributes( 90 {f"attributes__{LDAP_UNIQUENESS}": uniq}, defaults 91 ) 92 if not UserLDAPSourceConnection.objects.filter( 93 source=self._source, identifier=uniq 94 ): 95 UserLDAPSourceConnection.objects.create( 96 source=self._source, user=ak_user, identifier=uniq 97 ) 98 except PropertyMappingExpressionException as exc: 99 raise StopSync(exc, None, exc.mapping) from exc 100 except SkipObjectException: 101 continue 102 except (IntegrityError, FieldError, TypeError, AttributeError) as exc: 103 Event.new( 104 EventAction.CONFIGURATION_ERROR, 105 message=( 106 f"Failed to create user: {str(exc)} " 107 "To merge new user with existing user, set the user's " 108 f"Attribute '{LDAP_UNIQUENESS}' to '{uniq}'" 109 ), 110 source=self._source, 111 dn=user_dn, 112 ).save() 113 else: 114 self._logger.debug("Synced User", user=ak_user.username, created=created) 115 user_count += 1 116 MicrosoftActiveDirectory(self._source, self._task).sync( 117 attributes, ak_user, created 118 ) 119 FreeIPA(self._source, self._task).sync(attributes, ak_user, created) 120 return user_count
30class UserLDAPSynchronizer(BaseLDAPSynchronizer): 31 """Sync LDAP Users into authentik""" 32 33 def __init__(self, source: LDAPSource, task: Task): 34 super().__init__(source, task) 35 self.mapper = SourceMapper(source) 36 self.manager = self.mapper.get_manager(User, ["ldap", "dn"]) 37 38 @staticmethod 39 def name() -> str: 40 return "users" 41 42 def get_objects(self, **kwargs) -> Generator: 43 if not self._source.sync_users: 44 self._task.info("User syncing is disabled for this Source") 45 return iter(()) 46 return self.search_paginator( 47 search_base=self.base_dn_users, 48 search_filter=self._source.user_object_filter, 49 search_scope=SUBTREE, 50 attributes=[ 51 ALL_ATTRIBUTES, 52 ALL_OPERATIONAL_ATTRIBUTES, 53 self._source.object_uniqueness_field, 54 ], 55 **kwargs, 56 ) 57 58 def sync(self, page_data: list) -> int: 59 """Iterate over all LDAP Users and create authentik_core.User instances""" 60 if not self._source.sync_users: 61 self._task.info("User syncing is disabled for this Source") 62 return -1 63 user_count = 0 64 for user in page_data: 65 if (attributes := self.get_attributes(user)) is None: 66 continue 67 user_dn = flatten(user.get("entryDN", user.get("dn"))) 68 if not (uniq := self.get_identifier(attributes)): 69 self._task.info( 70 f"Uniqueness field not found/not set in attributes: '{user_dn}'", 71 attributes=list(attributes.keys()), 72 dn=user_dn, 73 ) 74 continue 75 try: 76 defaults = { 77 k: flatten(v) 78 for k, v in self.mapper.build_object_properties( 79 object_type=User, 80 manager=self.manager, 81 user=None, 82 request=None, 83 dn=user_dn, 84 ldap=attributes, 85 ).items() 86 } 87 self._logger.debug("Writing user with attributes", **defaults) 88 if "username" not in defaults: 89 raise IntegrityError("Username was not set by propertymappings") 90 ak_user, created = User.update_or_create_attributes( 91 {f"attributes__{LDAP_UNIQUENESS}": uniq}, defaults 92 ) 93 if not UserLDAPSourceConnection.objects.filter( 94 source=self._source, identifier=uniq 95 ): 96 UserLDAPSourceConnection.objects.create( 97 source=self._source, user=ak_user, identifier=uniq 98 ) 99 except PropertyMappingExpressionException as exc: 100 raise StopSync(exc, None, exc.mapping) from exc 101 except SkipObjectException: 102 continue 103 except (IntegrityError, FieldError, TypeError, AttributeError) as exc: 104 Event.new( 105 EventAction.CONFIGURATION_ERROR, 106 message=( 107 f"Failed to create user: {str(exc)} " 108 "To merge new user with existing user, set the user's " 109 f"Attribute '{LDAP_UNIQUENESS}' to '{uniq}'" 110 ), 111 source=self._source, 112 dn=user_dn, 113 ).save() 114 else: 115 self._logger.debug("Synced User", user=ak_user.username, created=created) 116 user_count += 1 117 MicrosoftActiveDirectory(self._source, self._task).sync( 118 attributes, ak_user, created 119 ) 120 FreeIPA(self._source, self._task).sync(attributes, ak_user, created) 121 return user_count
Sync LDAP Users into authentik
UserLDAPSynchronizer( source: authentik.sources.ldap.models.LDAPSource, task: authentik.tasks.models.Task)
def
get_objects(self, **kwargs) -> Generator:
42 def get_objects(self, **kwargs) -> Generator: 43 if not self._source.sync_users: 44 self._task.info("User syncing is disabled for this Source") 45 return iter(()) 46 return self.search_paginator( 47 search_base=self.base_dn_users, 48 search_filter=self._source.user_object_filter, 49 search_scope=SUBTREE, 50 attributes=[ 51 ALL_ATTRIBUTES, 52 ALL_OPERATIONAL_ATTRIBUTES, 53 self._source.object_uniqueness_field, 54 ], 55 **kwargs, 56 )
Get objects from LDAP, implemented in subclass
def
sync(self, page_data: list) -> int:
58 def sync(self, page_data: list) -> int: 59 """Iterate over all LDAP Users and create authentik_core.User instances""" 60 if not self._source.sync_users: 61 self._task.info("User syncing is disabled for this Source") 62 return -1 63 user_count = 0 64 for user in page_data: 65 if (attributes := self.get_attributes(user)) is None: 66 continue 67 user_dn = flatten(user.get("entryDN", user.get("dn"))) 68 if not (uniq := self.get_identifier(attributes)): 69 self._task.info( 70 f"Uniqueness field not found/not set in attributes: '{user_dn}'", 71 attributes=list(attributes.keys()), 72 dn=user_dn, 73 ) 74 continue 75 try: 76 defaults = { 77 k: flatten(v) 78 for k, v in self.mapper.build_object_properties( 79 object_type=User, 80 manager=self.manager, 81 user=None, 82 request=None, 83 dn=user_dn, 84 ldap=attributes, 85 ).items() 86 } 87 self._logger.debug("Writing user with attributes", **defaults) 88 if "username" not in defaults: 89 raise IntegrityError("Username was not set by propertymappings") 90 ak_user, created = User.update_or_create_attributes( 91 {f"attributes__{LDAP_UNIQUENESS}": uniq}, defaults 92 ) 93 if not UserLDAPSourceConnection.objects.filter( 94 source=self._source, identifier=uniq 95 ): 96 UserLDAPSourceConnection.objects.create( 97 source=self._source, user=ak_user, identifier=uniq 98 ) 99 except PropertyMappingExpressionException as exc: 100 raise StopSync(exc, None, exc.mapping) from exc 101 except SkipObjectException: 102 continue 103 except (IntegrityError, FieldError, TypeError, AttributeError) as exc: 104 Event.new( 105 EventAction.CONFIGURATION_ERROR, 106 message=( 107 f"Failed to create user: {str(exc)} " 108 "To merge new user with existing user, set the user's " 109 f"Attribute '{LDAP_UNIQUENESS}' to '{uniq}'" 110 ), 111 source=self._source, 112 dn=user_dn, 113 ).save() 114 else: 115 self._logger.debug("Synced User", user=ak_user.username, created=created) 116 user_count += 1 117 MicrosoftActiveDirectory(self._source, self._task).sync( 118 attributes, ak_user, created 119 ) 120 FreeIPA(self._source, self._task).sync(attributes, ak_user, created) 121 return user_count
Iterate over all LDAP Users and create authentik_core.User instances