authentik.sources.ldap.auth
authentik LDAP Authentication Backend
1"""authentik LDAP Authentication Backend""" 2 3from django.http import HttpRequest 4from ldap3.core.exceptions import LDAPException, LDAPInvalidCredentialsResult 5from structlog.stdlib import get_logger 6 7from authentik.core.auth import InbuiltBackend 8from authentik.core.models import User 9from authentik.sources.ldap.models import LDAP_DISTINGUISHED_NAME, LDAPSource 10 11LOGGER = get_logger() 12 13 14class LDAPBackend(InbuiltBackend): 15 """Authenticate users against LDAP Server""" 16 17 def authenticate(self, request: HttpRequest, **kwargs): 18 """Try to authenticate a user via ldap""" 19 if "password" not in kwargs: 20 return None 21 for source in LDAPSource.objects.filter(enabled=True): 22 LOGGER.debug("LDAP Auth attempt", source=source) 23 user = self.auth_user(request, source, **kwargs) 24 if user: 25 self.set_method("ldap", request, source=source) 26 return user 27 return None 28 29 def auth_user( 30 self, request: HttpRequest, source: LDAPSource, password: str, **filters: str 31 ) -> User | None: 32 """Try to bind as either user_dn or mail with password. 33 Returns True on success, otherwise False""" 34 users = User.objects.filter(**filters) 35 if not users.exists(): 36 return None 37 user: User = users.first() 38 if LDAP_DISTINGUISHED_NAME not in user.attributes: 39 LOGGER.debug("User doesn't have DN set, assuming not LDAP imported.", user=user) 40 return None 41 # Either has unusable password, 42 # or has a password, but couldn't be authenticated by ModelBackend. 43 # This means we check with a bind to see if the LDAP password has changed 44 if self.auth_user_by_bind(source, user, password): 45 if source.password_login_update_internal_password: 46 # Password given successfully binds to LDAP, so we save it in our Database 47 LOGGER.debug("Updating user's password in DB", user=user) 48 user.set_password(password, sender=source, request=request) 49 user.save() 50 return user 51 # Password doesn't match 52 LOGGER.debug("Failed to bind, password invalid") 53 return None 54 55 def auth_user_by_bind(self, source: LDAPSource, user: User, password: str) -> User | None: 56 """Attempt authentication by binding to the LDAP server as `user`. This 57 method should be avoided as its slow to do the bind.""" 58 # Try to bind as new user 59 LOGGER.debug("Attempting to bind as user", user=user) 60 try: 61 # source.connection also attempts to bind 62 source.connection( 63 connection_kwargs={ 64 "user": user.attributes.get(LDAP_DISTINGUISHED_NAME), 65 "password": password, 66 } 67 ) 68 return user 69 except LDAPInvalidCredentialsResult as exc: 70 LOGGER.debug("invalid LDAP credentials", user=user, exc=exc) 71 except LDAPException as exc: 72 LOGGER.warning("failed to bind to LDAP", exc=exc) 73 return None
LOGGER =
<BoundLoggerLazyProxy(logger=None, wrapper_class=None, processors=None, context_class=None, initial_values={}, logger_factory_args=())>
15class LDAPBackend(InbuiltBackend): 16 """Authenticate users against LDAP Server""" 17 18 def authenticate(self, request: HttpRequest, **kwargs): 19 """Try to authenticate a user via ldap""" 20 if "password" not in kwargs: 21 return None 22 for source in LDAPSource.objects.filter(enabled=True): 23 LOGGER.debug("LDAP Auth attempt", source=source) 24 user = self.auth_user(request, source, **kwargs) 25 if user: 26 self.set_method("ldap", request, source=source) 27 return user 28 return None 29 30 def auth_user( 31 self, request: HttpRequest, source: LDAPSource, password: str, **filters: str 32 ) -> User | None: 33 """Try to bind as either user_dn or mail with password. 34 Returns True on success, otherwise False""" 35 users = User.objects.filter(**filters) 36 if not users.exists(): 37 return None 38 user: User = users.first() 39 if LDAP_DISTINGUISHED_NAME not in user.attributes: 40 LOGGER.debug("User doesn't have DN set, assuming not LDAP imported.", user=user) 41 return None 42 # Either has unusable password, 43 # or has a password, but couldn't be authenticated by ModelBackend. 44 # This means we check with a bind to see if the LDAP password has changed 45 if self.auth_user_by_bind(source, user, password): 46 if source.password_login_update_internal_password: 47 # Password given successfully binds to LDAP, so we save it in our Database 48 LOGGER.debug("Updating user's password in DB", user=user) 49 user.set_password(password, sender=source, request=request) 50 user.save() 51 return user 52 # Password doesn't match 53 LOGGER.debug("Failed to bind, password invalid") 54 return None 55 56 def auth_user_by_bind(self, source: LDAPSource, user: User, password: str) -> User | None: 57 """Attempt authentication by binding to the LDAP server as `user`. This 58 method should be avoided as its slow to do the bind.""" 59 # Try to bind as new user 60 LOGGER.debug("Attempting to bind as user", user=user) 61 try: 62 # source.connection also attempts to bind 63 source.connection( 64 connection_kwargs={ 65 "user": user.attributes.get(LDAP_DISTINGUISHED_NAME), 66 "password": password, 67 } 68 ) 69 return user 70 except LDAPInvalidCredentialsResult as exc: 71 LOGGER.debug("invalid LDAP credentials", user=user, exc=exc) 72 except LDAPException as exc: 73 LOGGER.warning("failed to bind to LDAP", exc=exc) 74 return None
Authenticate users against LDAP Server
def
authenticate(self, request: django.http.request.HttpRequest, **kwargs):
18 def authenticate(self, request: HttpRequest, **kwargs): 19 """Try to authenticate a user via ldap""" 20 if "password" not in kwargs: 21 return None 22 for source in LDAPSource.objects.filter(enabled=True): 23 LOGGER.debug("LDAP Auth attempt", source=source) 24 user = self.auth_user(request, source, **kwargs) 25 if user: 26 self.set_method("ldap", request, source=source) 27 return user 28 return None
Try to authenticate a user via ldap
def
auth_user( self, request: django.http.request.HttpRequest, source: authentik.sources.ldap.models.LDAPSource, password: str, **filters: str) -> authentik.core.models.User | None:
30 def auth_user( 31 self, request: HttpRequest, source: LDAPSource, password: str, **filters: str 32 ) -> User | None: 33 """Try to bind as either user_dn or mail with password. 34 Returns True on success, otherwise False""" 35 users = User.objects.filter(**filters) 36 if not users.exists(): 37 return None 38 user: User = users.first() 39 if LDAP_DISTINGUISHED_NAME not in user.attributes: 40 LOGGER.debug("User doesn't have DN set, assuming not LDAP imported.", user=user) 41 return None 42 # Either has unusable password, 43 # or has a password, but couldn't be authenticated by ModelBackend. 44 # This means we check with a bind to see if the LDAP password has changed 45 if self.auth_user_by_bind(source, user, password): 46 if source.password_login_update_internal_password: 47 # Password given successfully binds to LDAP, so we save it in our Database 48 LOGGER.debug("Updating user's password in DB", user=user) 49 user.set_password(password, sender=source, request=request) 50 user.save() 51 return user 52 # Password doesn't match 53 LOGGER.debug("Failed to bind, password invalid") 54 return None
Try to bind as either user_dn or mail with password. Returns True on success, otherwise False
def
auth_user_by_bind( self, source: authentik.sources.ldap.models.LDAPSource, user: authentik.core.models.User, password: str) -> authentik.core.models.User | None:
56 def auth_user_by_bind(self, source: LDAPSource, user: User, password: str) -> User | None: 57 """Attempt authentication by binding to the LDAP server as `user`. This 58 method should be avoided as its slow to do the bind.""" 59 # Try to bind as new user 60 LOGGER.debug("Attempting to bind as user", user=user) 61 try: 62 # source.connection also attempts to bind 63 source.connection( 64 connection_kwargs={ 65 "user": user.attributes.get(LDAP_DISTINGUISHED_NAME), 66 "password": password, 67 } 68 ) 69 return user 70 except LDAPInvalidCredentialsResult as exc: 71 LOGGER.debug("invalid LDAP credentials", user=user, exc=exc) 72 except LDAPException as exc: 73 LOGGER.warning("failed to bind to LDAP", exc=exc) 74 return None
Attempt authentication by binding to the LDAP server as user. This
method should be avoided as its slow to do the bind.