etianen / django-python3-ldap

Django LDAP user authentication backend for Python 3.
BSD 3-Clause "New" or "Revised" License
410 stars 119 forks source link

User binding failed #72

Closed sebastianRudolf closed 4 years ago

sebastianRudolf commented 7 years ago

Hi

I have developed a Django app for the University of Cape Town and I am currently trying to hook it up with its Active Directory service.

I have tested python-ldap with Python 2.7.12 (default, Nov 19 2016, 06:48:10)

import ldap conn = ldap.initialize('ldap://') conn = ldap.initialize('ldap://137.158.157.86') conn.protocol_version = 3 conn.set_option(ldap.OPT_REFERRALS, 0) conn.simple_bind_s('01421894@wf.uct.ac.za','password') (97, [], 1, [])

which seems to work fine.

I have installed django-python3-ldap as outlined in the README and put the following lines in ./myapp/settings.py (Django 1.10)

AUTHENTICATION_BACKENDS = [ 'django_python3_ldap.auth.LDAPBackend', 'django.contrib.auth.backends.ModelBackend', ] LDAP_AUTH_URL = "ldap://msldap.uct.ac.za:636" LDAP_AUTH_USE_TLS = False LDAP_AUTH_SEARCH_BASE = "OU=UCT,DC=wf,DC=uct,DC=ac,DC=za" LDAP_AUTH_OBJECT_CLASS = "inetOrgPerson" LDAP_AUTH_USER_FIELDS = { "username": "uid", "first_name": "givenName", "last_name": "sn", "email": "mail", } LDAP_AUTH_USER_LOOKUP_FIELDS = ("username",) LDAP_AUTH_CLEAN_USER_DATA = "django_python3_ldap.utils.clean_user_data" LDAP_AUTH_SYNC_USER_RELATIONS = "django_python3_ldap.utils.sync_user_relations" LDAP_AUTH_FORMAT_SEARCH_FILTERS = "django_python3_ldap.utils.format_search_filters" LDAP_AUTH_FORMAT_USERNAME = "django_python3_ldap.utils.format_username_active_directory" LDAP_AUTH_ACTIVE_DIRECTORY_DOMAIN = "wf.uct.ac.za" LDAP_AUTH_CONNECTION_USERNAME = None LDAP_AUTH_CONNECTION_PASSWORD = None

Executing the test command: python manage.py ldap_sync_users produces the following which seems like no users have been found:

LDAP connect failed: error receiving data: [Errno 104] Connection reset by peer Traceback (most recent call last): File "manage.py", line 22, in execute_from_command_line(sys.argv) File "/usr/local/lib/python2.7/dist-packages/django/core/management/init.py", line 367, in execute_from_command_line utility.execute() File "/usr/local/lib/python2.7/dist-packages/django/core/management/init.py", line 359, in execute self.fetch_command(subcommand).run_from_argv(self.argv) File "/usr/local/lib/python2.7/dist-packages/django/core/management/base.py", line 294, in run_from_argv self.execute(*args, cmd_options) File "/usr/local/lib/python2.7/dist-packages/django/core/management/base.py", line 345, in execute output = self.handle(*args, *options) File "/usr/local/lib/python2.7/dist-packages/django/utils/decorators.py", line 185, in inner return func(args, kwargs) File "/usr/local/lib/python2.7/dist-packages/django_python3_ldap/management/commands/ldap_sync_users.py", line 19, in handle for user in connection.iter_users(): AttributeError: 'NoneType' object has no attribute 'iter_users'

I suspect it might be something quite trivial. Please advise.

Sebastian

etianen commented 7 years ago

"Connection reset by peer" means that the LDAP server unexpectedly slammed down the TCP connection.

This feels like a networking issue, or a configuration issue on the LDAP server.

On Fri, 7 Apr 2017 at 14:09 sebastianRudolf notifications@github.com wrote:

Hi

I have developed a Django app for the University of Cape Town and I am currently trying to hook it up with its Active Directory service.

I have tested python-ldap with Python 2.7.12 (default, Nov 19 2016, 06:48:10)

import ldap conn = ldap.initialize('ldap://') conn = ldap.initialize('ldap://137.158.157.86') conn.protocol_version = 3 conn.set_option(ldap.OPT_REFERRALS, 0) conn.simple_bind_s('01421894@wf.uct.ac.za','password') (97, [], 1, [])

which seems to work fine.

I have installed django-python3-ldap as outlined in the README and put the following lines in ./myapp/settings.py (Django 1.10)

AUTHENTICATION_BACKENDS = [ 'django_python3_ldap.auth.LDAPBackend', 'django.contrib.auth.backends.ModelBackend', ] LDAP_AUTH_URL = "ldap://msldap.uct.ac.za:636" LDAP_AUTH_USE_TLS = False LDAP_AUTH_SEARCH_BASE = "OU=UCT,DC=wf,DC=uct,DC=ac,DC=za" LDAP_AUTH_OBJECT_CLASS = "inetOrgPerson" LDAP_AUTH_USER_FIELDS = { "username": "uid", "first_name": "givenName", "last_name": "sn", "email": "mail", } LDAP_AUTH_USER_LOOKUP_FIELDS = ("username",) LDAP_AUTH_CLEAN_USER_DATA = "django_python3_ldap.utils.clean_user_data" LDAP_AUTH_SYNC_USER_RELATIONS = "django_python3_ldap.utils.sync_user_relations" LDAP_AUTH_FORMAT_SEARCH_FILTERS = "django_python3_ldap.utils.format_search_filters" LDAP_AUTH_FORMAT_USERNAME = "django_python3_ldap.utils.format_username_active_directory" LDAP_AUTH_ACTIVE_DIRECTORY_DOMAIN = "wf.uct.ac.za" LDAP_AUTH_CONNECTION_USERNAME = None LDAP_AUTH_CONNECTION_PASSWORD = None

Executing the test command: python manage.py ldap_sync_users produces the following which seems like no users have been found:

LDAP connect failed: error receiving data: [Errno 104] Connection reset by peer Traceback (most recent call last): File "manage.py", line 22, in execute_from_command_line(sys.argv) File "/usr/local/lib/python2.7/dist-packages/django/core/management/init.py", line 367, in execute_from_command_line utility.execute() File "/usr/local/lib/python2.7/dist-packages/django/core/management/init.py", line 359, in execute self.fetch_command(subcommand).run_from_argv(self.argv) File "/usr/local/lib/python2.7/dist-packages/django/core/management/base.py", line 294, in run_from_argv self.execute(*args, cmd_options) File "/usr/local/lib/python2.7/dist-packages/django/core/management/base.py", line 345, in execute output = self.handle(*args, *options) File "/usr/local/lib/python2.7/dist-packages/django/utils/decorators.py", line 185, in inner return func(args, kwargs) File "/usr/local/lib/python2.7/dist-packages/django_python3_ldap/management/commands/ldap_sync_users.py", line 19, in handle for user in connection.iter_users(): AttributeError: 'NoneType' object has no attribute 'iter_users'

I suspect it might be something quite trivial. Please advise.

Sebastian

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/etianen/django-python3-ldap/issues/72, or mute the thread https://github.com/notifications/unsubscribe-auth/AAJFCHphdClHr919uLAFvEH6iftUk_sUks5rtjV6gaJpZM4M24DP .

sebastianRudolf commented 7 years ago

Thanks for your response.

I would agree with you. When look at the Python script in question "ldap_sync_users.py"

def handle(self, *args, **kwargs):
    verbosity = int(kwargs.get("verbosity", 1))
    with ldap.connection(
        username=settings.LDAP_AUTH_CONNECTION_USERNAME,
        password=settings.LDAP_AUTH_CONNECTION_PASSWORD,
    ) as connection:
        for user in connection.iter_users():
            if verbosity >= 1:
                self.stdout.write("Synced {user}".format(
                    user=user,
                ))

The 'connection' object in line 7 is NoneType which indicates that the binding did not happen I guess.

Is there anything very obviously wrong of the LDAP settings in myapp/settings.py (see above in my first post)? The reason why I am asking is that the manual binding using my above test in the python shell above was successful.

etianen commented 7 years ago

I've pushed a fix to master to turn the NoneType error into something a bit nicer. But that wasn't actually your problem! :P

Some items in your settings that you might want to investigate:

  1. Try setting LDAP_AUTH_URL = "ldap://137.158.157.86". You're using different URLs in your raw Python versus Django settings.
  2. Try binding in your raw Python using an alternative username format, just to confirm that it's not django-python3-ldap's Active Directory username format: conn.simple_bind_s('wf.uct.ac.za 01421894@wf.uct.ac.za \01421894 01421894@wf.uct.ac.za','password')

On Tue, 11 Apr 2017 at 12:26 sebastianRudolf notifications@github.com wrote:

Thanks for your response.

I would agree with you. When look at the Python script in question "ldap_sync_users.py"

def handle(self, *args, **kwargs): verbosity = int(kwargs.get("verbosity", 1)) with ldap.connection( username=settings.LDAP_AUTH_CONNECTION_USERNAME, password=settings.LDAP_AUTH_CONNECTION_PASSWORD, ) as connection: for user in connection.iter_users(): if verbosity >= 1: self.stdout.write("Synced {user}".format( user=user, ))

The 'connection' object in line 7 is NoneType which indicates that the binding did not happen I guess.

Is there anything very obviously wrong of the LDAP settings in myapp/settings.py (see above in my first post)? The reason why I am asking is that the manual binding using my above test in the python shell above was successful.

— You are receiving this because you commented.

Reply to this email directly, view it on GitHub https://github.com/etianen/django-python3-ldap/issues/72#issuecomment-293228419, or mute the thread https://github.com/notifications/unsubscribe-auth/AAJFCAGW2naLZdmcHTJO_RE-0NnbKeYsks5ru2NYgaJpZM4M24DP .

sebastianRudolf commented 7 years ago

I have already tried LDAP_AUTH_URL = "ldap://137.158.157.86" which did not work (it did work for the manual binding test though).

Actually the ldap username format is XXXXXXXX@wf.uct.ac.za indeed, for all staff at UCT. The login to my server where I am running my Django app is via the same Active Directory service (my username is 01421894), as it is a UCT server machine.

What other username format could I use?

etianen commented 7 years ago

There are several ways to format an AD username. Try using this line instead of the one you had:

conn.simple_bind_s('wf.uct.ac.za 01421894@wf.uct.ac.za\01421894 01421894@wf.uct.ac.za','password')

(The domain first, separated by the username by a backslash)

On Tue, 11 Apr 2017 at 14:20 sebastianRudolf notifications@github.com wrote:

I have already tried LDAP_AUTH_URL = "ldap://137.158.157.86" which did not work (it did work for the manual binding test though).

Actually the ldap username format is XXXXXXXX@wf.uct.ac.za indeed, for all staff at UCT. The login to my server where I am running my Django app is via the same Active Directory service (my username is 01421894), as it is a UCT server machine.

What other username format could I use?

— You are receiving this because you commented.

Reply to this email directly, view it on GitHub https://github.com/etianen/django-python3-ldap/issues/72#issuecomment-293259854, or mute the thread https://github.com/notifications/unsubscribe-auth/AAJFCN044ydNx4BVRumxJOtACMADFL_xks5ru34UgaJpZM4M24DP .

sebastianRudolf commented 7 years ago

Hm, if I do an exact copy-paste of your formatting suggestion, i.e.

conn.simple_bind_s('wf.uct.ac.za 01421894@wf.uct.ac.za\01421894 01421894@wf.uct.ac.za','password')

this does not work.

I also tried (in case I misunderstood you):

conn2.simple_bind_s('wf.uct.ac.za\01421894','password')

which did not work either.

etianen commented 7 years ago

Try your second one, with two backslashes, as you have to escape backslashes in Python strings. On Tue, 11 Apr 2017 at 18:43, sebastianRudolf notifications@github.com wrote:

Hm, if I do an exact copy-paste of your formatting suggesting, i.e.

conn.simple_bind_s('wf.uct.ac.za 01421894@wf.uct.ac.za\01421894 01421894@wf.uct.ac.za','password')

this does not work.

I also tried (in case I misunderstood you):

conn2.simple_bind_s('wf.uct.ac.za\01421894','password')

which did not work either.

— You are receiving this because you commented.

Reply to this email directly, view it on GitHub https://github.com/etianen/django-python3-ldap/issues/72#issuecomment-293341553, or mute the thread https://github.com/notifications/unsubscribe-auth/AAJFCLjp8_Rj2-HqT4-ksgYs7FOQU9_Mks5ru7vEgaJpZM4M24DP .

etianen commented 7 years ago

I've just added support for the email-style usernames:

https://github.com/etianen/django-python3-ldap#microsoft-active-directory-support

Upgrade to the master branch, then use these settings:

AUTHENTICATION_BACKENDS = [
    'django_python3_ldap.auth.LDAPBackend',
    'django.contrib.auth.backends.ModelBackend',
]
LDAP_AUTH_URL = "ldap://msldap.uct.ac.za:636"
LDAP_AUTH_USE_TLS = False
LDAP_AUTH_SEARCH_BASE = "OU=UCT,DC=wf,DC=uct,DC=ac,DC=za"
LDAP_AUTH_OBJECT_CLASS = "inetOrgPerson"
LDAP_AUTH_USER_FIELDS = {
    "username": "uid",
    "first_name": "givenName",
    "last_name": "sn",
    "email": "mail",
}
LDAP_AUTH_USER_LOOKUP_FIELDS = ("username",)
LDAP_AUTH_CLEAN_USER_DATA = "django_python3_ldap.utils.clean_user_data"
LDAP_AUTH_SYNC_USER_RELATIONS = "django_python3_ldap.utils.sync_user_relations"
LDAP_AUTH_FORMAT_SEARCH_FILTERS = "django_python3_ldap.utils.format_search_filters"
LDAP_AUTH_FORMAT_USERNAME = "django_python3_ldap.utils.format_username_active_directory_principal"
LDAP_AUTH_ACTIVE_DIRECTORY_DOMAIN = "wf.uct.ac.za"
LDAP_AUTH_CONNECTION_USERNAME = None
LDAP_AUTH_CONNECTION_PASSWORD = None
sebastianRudolf commented 7 years ago

hi Noting your changes, I have done an update: pip install -U django-python3-ldap

Then I tried to establish a simple binding as instructed by you but that did not work:

Python 2.7.12 (default, Nov 19 2016, 06:48:10) [GCC 5.4.0 20160609] on linux2 Type "help", "copyright", "credits" or "license" for more information.

import ldap conn = ldap.initialize('ldap://') conn = ldap.initialize('ldap://msldap.uct.ac.za') conn.protocol_version = 3 conn.set_option(ldap.OPT_REFERRALS, 0) conn.simple_bind_s('wf.uct.ac.za\01421894','password') Traceback (most recent call last): File "", line 1, in File "/usr/local/lib/python2.7/dist-packages/ldap/ldapobject.py", line 223, in simple_bind_s resp_type, resp_data, resp_msgid, resp_ctrls = self.result3(msgid,all=1,timeout=self.timeout) File "/usr/local/lib/python2.7/dist-packages/ldap/ldapobject.py", line 514, in result3 resp_ctrl_classes=resp_ctrl_classes File "/usr/local/lib/python2.7/dist-packages/ldap/ldapobject.py", line 521, in result4 ldap_result = self._ldap_call(self._l.result4,msgid,all,timeout,add_ctrls,add_intermediates,add_extop) File "/usr/local/lib/python2.7/dist-packages/ldap/ldapobject.py", line 106, in _ldap_call result = func(*args,**kwargs) ldap.INVALID_CREDENTIALS: {'info': '80090308: LdapErr: DSID-0C0903A8, comment: AcceptSecurityContext error, data 52e, v1db1', 'desc': 'Invalid credentials'} conn.simple_bind_s('01421894@wf.uct.ac.za','password') (97, [], 2, [])

etianen commented 7 years ago

Hmm, sorry, that's not what I meant.

For the simple binding, you should use:

import ldap
conn = ldap.initialize('ldap://')
conn = ldap.initialize('ldap://msldap.uct.ac.za:636')
conn.protocol_version = 3
conn.set_option(ldap.OPT_REFERRALS, 0)
conn.simple_bind_s('01421894@wf.uct.ac.za','password')

This maps to the following Django settings:

AUTHENTICATION_BACKENDS = [
    'django_python3_ldap.auth.LDAPBackend',
    'django.contrib.auth.backends.ModelBackend',
]
LDAP_AUTH_URL = "ldap://msldap.uct.ac.za:636"
LDAP_AUTH_USE_TLS = False
LDAP_AUTH_SEARCH_BASE = "OU=UCT,DC=wf,DC=uct,DC=ac,DC=za"
LDAP_AUTH_OBJECT_CLASS = "inetOrgPerson"
LDAP_AUTH_USER_FIELDS = {
    "username": "uid",
    "first_name": "givenName",
    "last_name": "sn",
    "email": "mail",
}
LDAP_AUTH_USER_LOOKUP_FIELDS = ("username",)
LDAP_AUTH_CLEAN_USER_DATA = "django_python3_ldap.utils.clean_user_data"
LDAP_AUTH_SYNC_USER_RELATIONS = "django_python3_ldap.utils.sync_user_relations"
LDAP_AUTH_FORMAT_SEARCH_FILTERS = "django_python3_ldap.utils.format_search_filters"
LDAP_AUTH_FORMAT_USERNAME = "django_python3_ldap.utils.format_username_active_directory_principal"
LDAP_AUTH_ACTIVE_DIRECTORY_DOMAIN = "wf.uct.ac.za"
LDAP_AUTH_CONNECTION_USERNAME = None
LDAP_AUTH_CONNECTION_PASSWORD = None
sebastianRudolf commented 7 years ago

I also did the 2 suggested changes in 'myapp/settings.py'

LDAP_AUTH_URL = "ldap://msldap.uct.ac.za:636" LDAP_AUTH_FORMAT_USERNAME = "django_python3_ldap.utils.format_username_active_directory_principal"

(the remaining settings are unchanged).

Executing the test script I get the following:

01421894$:/var/www/seat$ python manage.py ldap_sync_users LDAP connect failed: error receiving data: [Errno 104] Connection reset by peer CommandError: Could not connect to LDAP server

etianen commented 7 years ago

I wonder what the difference is between the Django config, and the raw python script?

Does this work (no protocol version):

import ldap
conn = ldap.initialize('ldap://')
conn = ldap.initialize('ldap://msldap.uct.ac.za:636')
# conn.protocol_version = 3
conn.set_option(ldap.OPT_REFERRALS, 0)
conn.simple_bind_s('01421894@wf.uct.ac.za','password')
sebastianRudolf commented 7 years ago

It looks like our AD server is down now. I have contacted our IT department to check.

conn2 = ldap.initialize('ldap://') conn2 = ldap.initialize('ldap://msldap.uct.ac.za:636') conn2.set_option(ldap.OPT_REFERRALS, 0) conn2.simple_bind_s('01421894@wf.uct.ac.za','password') Traceback (most recent call last): File "", line 1, in File "/usr/local/lib/python2.7/dist-packages/ldap/ldapobject.py", line 223, in simple_bind_s resp_type, resp_data, resp_msgid, resp_ctrls = self.result3(msgid,all=1,timeout=self.timeout) File "/usr/local/lib/python2.7/dist-packages/ldap/ldapobject.py", line 514, in result3 resp_ctrl_classes=resp_ctrl_classes File "/usr/local/lib/python2.7/dist-packages/ldap/ldapobject.py", line 521, in result4 ldap_result = self._ldap_call(self._l.result4,msgid,all,timeout,add_ctrls,add_intermediates,add_extop) File "/usr/local/lib/python2.7/dist-packages/ldap/ldapobject.py", line 106, in _ldap_call result = func(*args,**kwargs) ldap.SERVER_DOWN: {'desc': "Can't contact LDAP server"}

sebastianRudolf commented 7 years ago

I checked with UCT's IT department, the AD server msldap.uct.ac.za is definitely not down.

I think, since updated the django-python3-ldap module, the simple manual binding does not work anymore:

$ python Python 2.7.12 (default, Nov 19 2016, 06:48:10) [GCC 5.4.0 20160609] on linux2 Type "help", "copyright", "credits" or "license" for more information.

import ldap conn = ldap.initialize('ldap://') conn = ldap.initialize('ldap://msldap.uct.ac.za:636') conn.protocol_version = 3 conn.set_option(ldap.OPT_REFERRALS, 0) conn.simple_bind_s('01421894@wf.uct.ac.za','password') Traceback (most recent call last): File "", line 1, in File "/usr/local/lib/python2.7/dist-packages/ldap/ldapobject.py", line 223, in simple_bind_s resp_type, resp_data, resp_msgid, resp_ctrls = self.result3(msgid,all=1,timeout=self.timeout) File "/usr/local/lib/python2.7/dist-packages/ldap/ldapobject.py", line 514, in result3 resp_ctrl_classes=resp_ctrl_classes File "/usr/local/lib/python2.7/dist-packages/ldap/ldapobject.py", line 521, in result4 ldap_result = self._ldap_call(self._l.result4,msgid,all,timeout,add_ctrls,add_intermediates,add_extop) File "/usr/local/lib/python2.7/dist-packages/ldap/ldapobject.py", line 106, in _ldap_call result = func(*args,**kwargs) ldap.SERVER_DOWN: {'desc': "Can't contact LDAP server"}

etianen commented 7 years ago

Hmm.

If you can get it working with the simple manual binding, I can tell you how to link that up to django-python3-ldap. But without that, I'm afraid I'm stuck.

Try connecting to the LDAP server using telnet, just to make sure that the django machine can connect to it?

sebastianRudolf commented 7 years ago

By accident, I left the port number away and it worked for the simple manual binding:

$ python Python 2.7.12 (default, Nov 19 2016, 06:48:10) [GCC 5.4.0 20160609] on linux2 Type "help", "copyright", "credits" or "license" for more information.

import ldap conn = ldap.initialize('ldap://' + 'msldap.uct.ac.za') conn.protocol_version = 3 conn.simple_bind_s('01421894@wf.uct.ac.za','password') (97, [], 1, [])

I also tried again the test script of your module removing in myapp/settings.py the port number and I got the following output:

python manage.py ldap_sync_users LDAP connect failed: LDAPOperationsErrorResult - 1 - operationsError - None - 000004DC: LdapErr: DSID-0C0906E8, comment: In order to perform this operation a successful bind must be completed on the connection., data 0, v1db1 - searchResDone - None CommandError: Could not connect to LDAP server

Perhaps, I need to specify a different port number?

etianen commented 7 years ago

By the looks of things, your simple manual binding is using the python-ldap package, rather than ldap3?

It might be best if you debug this using the ldap3 package, since that's what django-python3-ldap uses. Try getting something like this to work:

https://gist.github.com/etianen/34b2567bc957acaf7ac4d854d6f82f27

Once you've got that working, translating it into Django settings should be easy.

On Wed, 19 Apr 2017 at 15:40 sebastianRudolf notifications@github.com wrote:

By accident, I left the port number away and it worked for the simple manual binding:

$ python

Python 2.7.12 (default, Nov 19 2016, 06:48:10) [GCC 5.4.0 20160609] on linux2 Type "help", "copyright", "credits" or "license" for more information.

import ldap conn = ldap.initialize('ldap://' + 'msldap.uct.ac.za') conn.protocol_version = 3

conn.simple_bind_s('01421894@wf.uct.ac.za','password') (97, [], 1, [])

I also tried again the test script of your module removing in myapp/settings.py the port number and I got the following output:

python manage.py ldap_sync_users LDAP connect failed: LDAPOperationsErrorResult - 1 - operationsError - None - 000004DC: LdapErr: DSID-0C0906E8, comment: In order to perform this operation a successful bind must be completed on the connection., data 0, v1db1 - searchResDone - None

CommandError: Could not connect to LDAP server

Perhaps, I need to specify a different port number?

— You are receiving this because you commented.

Reply to this email directly, view it on GitHub https://github.com/etianen/django-python3-ldap/issues/72#issuecomment-295293562, or mute the thread https://github.com/notifications/unsubscribe-auth/AAJFCBDGhkgnFtXvHhNFq7sKQnmFkbFEks5rxhzjgaJpZM4M24DP .

sebastianRudolf commented 7 years ago

True, thanks for pointing this out.

I checked out the script where you provided the link and it seems to work with ldap3:

$ python Python 2.7.12 (default, Nov 19 2016, 06:48:10) [GCC 5.4.0 20160609] on linux2 Type "help", "copyright", "credits" or "license" for more information.

import ldap3 ldap3.Connection( ... ldap3.Server( ... "ldap://msldap.uct.ac.za", ... allowed_referral_hosts=[("", True)], ... ), ... user="01421894@wf.uct.ac.za", ... password="password", ... auto_bind=ldap3.AUTO_BIND_NO_TLS, ... raise_exceptions=True, ... ) Connection(server=Server(host='msldap.uct.ac.za', port=389, use_ssl=False, allowed_referral_hosts=[('', True)], get_info='SCHEMA'), user='01421894@wf.uct.ac.za', password='password', auto_bind='NO_TLS', version=3, authentication='SIMPLE', client_strategy='SYNC', auto_referrals=True, check_names=True, read_only=False, lazy=False, raise_exceptions=True, fast_decoder=True, auto_range=True, return_empty_attributes=True)

etianen commented 7 years ago

Based on that, I think your settings should be:

LDAP_AUTH_URL = "ldap://msldap.uct.ac.za"
LDAP_AUTH_FORMAT_USERNAME = "django_python3_ldap.utils.format_username_active_directory_principal"
LDAP_AUTH_ACTIVE_DIRECTORY_DOMAIN = "wf.uct.ac.za""
sebastianRudolf commented 7 years ago

This is what I am already using but it gives me the following error:

/var/www/seat$ python manage.py ldap_sync_users LDAP connect failed: LDAPOperationsErrorResult - 1 - operationsError - None - 000004DC: LdapErr: DSID-0C0906E8, comment: In order to perform this operation a successful bind must be completed on the connection., data 0, v1db1 - searchResDone - None CommandError: Could not connect to LDAP server

By the way, my Django installation makes use of Python 2.7.12 (not Python3). Also, does your test script require special access rights to the MyApp installation directory (/var/www/seat)? Currently user and group is 'www-data'.

Below LDAP relevant content of settings.py:

AUTHENTICATION_BACKENDS = [ 'django_python3_ldap.auth.LDAPBackend', 'django.contrib.auth.backends.ModelBackend', ] LDAP_AUTH_URL = "ldap://msldap.uct.ac.za" LDAP_AUTH_USE_TLS = False LDAP_AUTH_SEARCH_BASE = "OU=UCT,DC=wf,DC=uct,DC=ac,DC=za" LDAP_AUTH_OBJECT_CLASS = "inetOrgPerson" LDAP_AUTH_USER_FIELDS = { "username": "uid", "first_name": "givenName", "last_name": "sn", "email": "mail", } LDAP_AUTH_USER_LOOKUP_FIELDS = ("username",) LDAP_AUTH_CLEAN_USER_DATA = "django_python3_ldap.utils.clean_user_data" LDAP_AUTH_SYNC_USER_RELATIONS = "django_python3_ldap.utils.sync_user_relations" LDAP_AUTH_FORMAT_SEARCH_FILTERS = "django_python3_ldap.utils.format_search_filters" LDAP_AUTH_FORMAT_USERNAME = "django_python3_ldap.utils.format_username_active_directory_principal" LDAP_AUTH_ACTIVE_DIRECTORY_DOMAIN = "wf.uct.ac.za" LDAP_AUTH_CONNECTION_USERNAME = None LDAP_AUTH_CONNECTION_PASSWORD = None LOGGING = { "version": 1, "disable_existing_loggers": False, "handlers": { "console": { "class": "logging.StreamHandler", }, }, "loggers": { "django_python3_ldap": { "handlers": ["console"], "level": "INFO", }, }, }

etianen commented 7 years ago

Aha!

LDAP_AUTH_CONNECTION_USERNAME = "01421894"
LDAP_AUTH_CONNECTION_PASSWORD = "password"
etianen commented 7 years ago

Looks like your server isn't set up for anonymous queries, so you need to hardcode a username and password in the config file.

sebastianRudolf commented 7 years ago

OK, I set username and password in the myapp/settings.py as suggest and I get the following error:

$ python manage.py ldap_sync_users Traceback (most recent call last): File "manage.py", line 22, in execute_from_command_line(sys.argv) File "/usr/local/lib/python2.7/dist-packages/django/core/management/init.py", line 363, in execute_from_command_line utility.execute() File "/usr/local/lib/python2.7/dist-packages/django/core/management/init.py", line 355, in execute self.fetch_command(subcommand).run_from_argv(self.argv) File "/usr/local/lib/python2.7/dist-packages/django/core/management/base.py", line 283, in run_from_argv self.execute(*args, cmd_options) File "/usr/local/lib/python2.7/dist-packages/django/core/management/base.py", line 330, in execute output = self.handle(*args, *options) File "/usr/local/lib/python2.7/dist-packages/django/utils/decorators.py", line 185, in inner return func(args, kwargs) File "/usr/local/lib/python2.7/dist-packages/django_python3_ldap/management/commands/ldap_sync_users.py", line 17, in handle password=settings.LDAP_AUTH_CONNECTION_PASSWORD, File "/usr/lib/python2.7/contextlib.py", line 17, in enter return self.gen.next() File "/usr/local/lib/python2.7/dist-packages/django_python3_ldap/ldap.py", line 132, in connection username = import_func(settings.LDAP_AUTH_FORMAT_USERNAME)(kwargs) File "/usr/local/lib/python2.7/dist-packages/django_python3_ldap/utils.py", line 19, in import_func return import_string(func) File "/usr/local/lib/python2.7/dist-packages/django/utils/module_loading.py", line 27, in import_string six.reraise(ImportError, ImportError(msg), sys.exc_info()[2]) File "/usr/local/lib/python2.7/dist-packages/django/utils/module_loading.py", line 23, in import_string return getattr(module, class_name) ImportError: Module "django_python3_ldap.utils" does not define a "format_username_active_directory_principal" attribute/class

etianen commented 7 years ago

You need to use the latest master branch.

On Thu, 27 Apr 2017 at 17:02 sebastianRudolf notifications@github.com wrote:

OK, I set username and password in the myapp/settings.py as suggest and I get the following error:

$ python manage.py ldap_sync_users

Traceback (most recent call last): File "manage.py", line 22, in execute_from_command_line(sys.argv)

File "/usr/local/lib/python2.7/dist-packages/django/core/management/init.py", line 363, in execute_from_command_line utility.execute() File "/usr/local/lib/python2.7/dist-packages/django/core/management/init.py", line 355, in execute self.fetch_command(subcommand).run_from_argv(self.argv) File "/usr/local/lib/python2.7/dist-packages/django/core/management/base.py", line 283, in run_from_argv self.execute(*args, **cmd_options) File "/usr/local/lib/python2.7/dist-packages/django/core/management/base.py", line 330, in execute

output = self.handle(*args, *options) File "/usr/local/lib/python2.7/dist-packages/django/utils/decorators.py", line 185, in inner return func(args, **kwargs)

File "/usr/local/lib/python2.7/dist-packages/django_python3_ldap/management/commands/ldap_sync_users.py", line 17, in handle password=settings.LDAP_AUTH_CONNECTION_PASSWORD, File "/usr/lib/python2.7/contextlib.py", line 17, in enter return self.gen.next() File "/usr/local/lib/python2.7/dist-packages/django_python3_ldap/ldap.py", line 132, in connection username = import_func(settings.LDAP_AUTH_FORMAT_USERNAME)(kwargs) File "/usr/local/lib/python2.7/dist-packages/django_python3_ldap/utils.py", line 19, in import_func return import_string(func) File "/usr/local/lib/python2.7/dist-packages/django/utils/module_loading.py", line 27, in import_string six.reraise(ImportError, ImportError(msg), sys.exc_info()[2]) File "/usr/local/lib/python2.7/dist-packages/django/utils/module_loading.py", line 23, in import_string return getattr(module, class_name) ImportError: Module "django_python3_ldap.utils" does not define a "format_username_active_directory_principal" attribute/class

— You are receiving this because you commented.

Reply to this email directly, view it on GitHub https://github.com/etianen/django-python3-ldap/issues/72#issuecomment-297759003, or mute the thread https://github.com/notifications/unsubscribe-auth/AAJFCFIaNNPJ_AXD4XtkKsZgMehti6-Oks5r0Lv1gaJpZM4M24DP .

wessven commented 2 years ago

I had this exact same issue. Although I was not using django-python3-ldap, I was using Django, Python 3 and python-ldap. I thought I would share my experience here for posterity.

I work for an international company (although, coincidentally, I am also based in Cape Town). I built an internal application to authenticate against our Active Directory server. No matter what I tried, the first authentication attempt always failed with "connection reset by peer". The second attempt would work.

I eventually figured out that the problem lay with the F5 load balancer the company uses. If I bypassed the load balancer, I could successfully authenticate my Django application against Active Directory on the first attempt. There was no problem with the code: it was a network issue.

Our IT department is still investigating why the load balancer causes this issue. In the meantime, I have implemented a simple function for AUTH_LDAP_SERVER_URI which selects a random authentication server to use (a thread probes the servers and marks them as down if they don't respond).

I hope that, if someone else has the misfortune to encounter this issue, that this answer helps them.

etianen commented 2 years ago

Thanks for the report! This is going to make somebody's day, someday!