I have plugged in this class as an authentication backend in django
class ActiveDirectoryBackend(object):
logger = Messenger.infrastructure
@classmethod
def authenticate(cls, username=None, password=None):
try:
bind_dn = "%s@%s" % (username, settings.AD_DNS_NAME)
try:
cls.logger.debug('Initializing: %s' % settings.AD_LDAP_URL)
l = ldap.initialize(settings.AD_LDAP_URL)
l.protocol_version = ldap.VERSION3
l.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER)
cls.logger.debug('Binding user %s' % bind_dn)
l.simple_bind_s(bind_dn, password)
result = l.search_ext_s(settings.AD_SEARCH_DN, ldap.SCOPE_SUBTREE,
"sAMAccountName=%s" % username, settings.AD_SEARCH_FIELDS)[0][1]
email = result.get('mail', (None,))[0]
except ldap.SERVER_DOWN, ex:
cls.logger.warning('LDAP-Sever Down (%s)' % ex.message)
raise PermissionDenied
except ldap.INVALID_CREDENTIALS:
cls.logger.warning('LDAP-Server: Rejected login for user %s due to invalid credentials' % username)
raise PermissionDenied
cls.logger.debug('User %s was successfully authorized.' % username)
l.unbind_s()
except Exception:
raise PermissionDenied
try:
user = User.objects.get(email=email)
cls.logger.debug('User %s found for email %s ' % (user.username, email))
except ObjectDoesNotExist, ex:
cls.logger.debug('User for email %s could not be found.' % email)
raise PermissionDenied
return user
The whole thing is running under Apache + uWSGI. When I run Django standalone (manage.py runserver) everything works fine with LDAP and LDAPS.
But when running it under uWSGI with LDAPS it always throws "Server Down". LDAP (w/o 's') works. Using tcpdump I can see packets going in both directions between AD and my server.
How does uWSGI influence the LDAPS communication between python-ldap or the underlying libraries and the Active Directory?
By playing around with the options on commandline ldapsearch a colleague and me found out what resolves the problem - but not what exactly caused the problem in the first place.
By explicitly setting the HOST option, we got it to work.
In python it looks like this:
l.set_option(ldap.OPT_HOST_NAME, settings.AD_DNS_NAME)