Coder Social home page Coder Social logo

django-python3-ldap's People

Contributors

alizain avatar aritas1 avatar audiolion avatar borislaviv avatar cristopherh95 avatar ernest0x avatar etianen avatar fladi avatar flipperpa avatar frennkie avatar gagantrivedi avatar githubuserx avatar hho6643 avatar kevin-olbrich avatar kishorkunal-raj avatar leavest avatar levisaya avatar matrixise avatar nigelm avatar notsqrt avatar ricard33 avatar saraheiting avatar smills2929 avatar sn1c avatar stinovlas avatar trs80 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

django-python3-ldap's Issues

user passwords is not sync | users only created at sync not at login

I have ben trying to get this working on a small site, with ad integration. I have come as far as i have it importing my users just fine, but i cant seem to be able to log into the site with them.

i have these settings in my settings.py and as i said i can sync the users just fine. But when i look at them in the django admin, it says their passwords are empty/not set?

AUTHENTICATION_BACKENDS = (
    'django.contrib.auth.backends.ModelBackend',
    'django_python3_ldap.auth.LDAPBackend',
    )`

`#LDAP START

# The URL of the LDAP server.
LDAP_AUTH_URL = "ldap://10.10.0.21:389"

# Initiate TLS on connection.
LDAP_AUTH_USE_TLS = False

# The LDAP search base for looking up users.
LDAP_AUTH_SEARCH_BASE = "OU=.site.local,DC=site,DC=local"

# The LDAP class that represents a user.
#LDAP_AUTH_OBJECT_CLASS = "inetOrgPerson"
LDAP_AUTH_OBJECT_CLASS = "organizationalPerson"
# User model fields mapped to the LDAP
# attributes that represent them.
LDAP_AUTH_USER_FIELDS = {
    "username": "sAMAccountName",
    "first_name": "givenName",
    "last_name": "sn",
    "email": "mail",
}

# A tuple of django model fields used to uniquely identify a user.
LDAP_AUTH_USER_LOOKUP_FIELDS = ("username",)

# Path to a callable that takes a dict of {model_field_name: value},
# returning a dict of clean model data.
# Use this to customize how data loaded from LDAP is saved to the User model.
LDAP_AUTH_CLEAN_USER_DATA = "django_python3_ldap.utils.clean_user_data"

# Path to a callable that takes a user model and a dict of {ldap_field_name: [value]},
# and saves any additional user relationships based on the LDAP data.
# Use this to customize how data loaded from LDAP is saved to User model relations.
# For customizing non-related User model fields, use LDAP_AUTH_CLEAN_USER_DATA.
LDAP_AUTH_SYNC_USER_RELATIONS = "django_python3_ldap.utils.sync_user_relations"

# Path to a callable that takes a dict of {ldap_field_name: value},
# returning a list of [ldap_search_filter]. The search filters will then be AND'd
# together when creating the final search filter.
LDAP_AUTH_FORMAT_SEARCH_FILTERS = "django_python3_ldap.utils.format_search_filters"

# Path to a callable that takes a dict of {model_field_name: value}, and returns
# a string of the username to bind to the LDAP server.
# Use this to support different types of LDAP server.
LDAP_AUTH_FORMAT_USERNAME = "django_python3_ldap.utils.format_username_active_directory"

# Sets the login domain for Active Directory users.
LDAP_AUTH_ACTIVE_DIRECTORY_DOMAIN = None

# The LDAP username and password of a user for authenticating the `ldap_sync_users`
# management command. Set to None if you allow anonymous queries.
LDAP_AUTH_CONNECTION_USERNAME = '[email protected]'
LDAP_AUTH_CONNECTION_PASSWORD = 'xxxxxx'

#LDAP_AUTH_ACTIVE_DIRECTORY_DOMAIN = "site.local"
#LDAP SLUT`

If i manualy define a password for the user in admin page, i can login just fine... so what am i missing?

i also tried to map the password field like this with no luck

LDAP_AUTH_USER_FIELDS = {
    "username": "sAMAccountName",
    "first_name": "givenName",
    "last_name": "sn",
    "email": "mail",
    "password": "userPassword",
}

Another isue i have, is the users is only being created when i use the sync command, not when they try to login? do i need to add anything to my views.py?

Using LDAP_AUTH_FORMAT_USERNAME = "django_python3_ldap.utils.format_username_active_directory_principal" doesnt work

config snippet:
`LDAP_AUTH_SEARCH_BASE = "ou=Benutzer,dc=test,dc=domain,dc=de"

LDAP_AUTH_ACTIVE_DIRECTORY_DOMAIN = "test.doamin.de"

LDAP_AUTH_CONNECTION_USERNAME = "username"
LDAP_AUTH_CONNECTION_PASSWORD = "password"

LDAP_AUTH_FORMAT_USERNAME = "django_python3_ldap.utils.format_username_active_directory_principal"
LDAP_AUTH_ACTIVE_DIRECTORY_DOMAIN = "test.doamin.de"

LOGGING = {
"version": 1,
"disable_existing_loggers": False,
"handlers": {
"console": {
"class": "logging.StreamHandler",
},
},
"loggers": {
"django_python3_ldap": {
"handlers": ["console"],
"level": "INFO",
},
},
}`
crashes with

`Traceback (most recent call last):
File "C:\Users\Tobias Liese\AppData\Local\Programs\Python\Python36\lib\site-packages\django\utils\module_loading.py", line 23, in import_string
return getattr(module, class_name)
AttributeError: module 'django_python3_ldap.utils' has no attribute 'format_username_active_directory_principal'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "manage.py", line 22, in
execute_from_command_line(sys.argv)
File "C:\Users\Tobias Liese\AppData\Local\Programs\Python\Python36\lib\site-packages\django\core\management_init_.py", line 363, in execute_from_command_line
utility.execute()
File "C:\Users\Tobias Liese\AppData\Local\Programs\Python\Python36\lib\site-packages\django\core\management_init_.py", line 355, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "C:\Users\Tobias Liese\AppData\Local\Programs\Python\Python36\lib\site-packages\django\core\management\base.py", line 283, in run_from_argv
self.execute(*args, **cmd_options)
File "C:\Users\Tobias Liese\AppData\Local\Programs\Python\Python36\lib\site-packages\django\core\management\base.py", line 330, in execute
output = self.handle(*args, **options)
File "C:\Users\Tobias Liese\AppData\Local\Programs\Python\Python36\lib\contextlib.py", line 53, in inner
return func(*args, **kwds)
File "C:\Users\Tobias Liese\AppData\Local\Programs\Python\Python36\lib\site-packages\django_python3_ldap\management\commands\ldap_sync_users.py", line 17, in handle
password=settings.LDAP_AUTH_CONNECTION_PASSWORD,
File "C:\Users\Tobias Liese\AppData\Local\Programs\Python\Python36\lib\contextlib.py", line 82, in enter
return next(self.gen)
File "C:\Users\Tobias Liese\AppData\Local\Programs\Python\Python36\lib\site-packages\django_python3_ldap\ldap.py", line 132, in connection
username = import_func(settings.LDAP_AUTH_FORMAT_USERNAME)(kwargs)
File "C:\Users\Tobias Liese\AppData\Local\Programs\Python\Python36\lib\site-packages\django_python3_ldap\utils.py", line 19, in import_func
return import_string(func)
File "C:\Users\Tobias Liese\AppData\Local\Programs\Python\Python36\lib\site-packages\django\utils\module_loading.py", line 27, in import_string
six.reraise(ImportError, ImportError(msg), sys.exc_info()[2])
File "C:\Users\Tobias Liese\AppData\Local\Programs\Python\Python36\lib\site-packages\django\utils\six.py", line 685, in reraise
raise value.with_traceback(tb)
File "C:\Users\Tobias Liese\AppData\Local\Programs\Python\Python36\lib\site-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`

when running: python manage.py ldap_sync_users

Add a setting for generic filtering of LDAP entries

Currently there is no setting for generic filtering of LDAP entries. It is only possible to filter for the object class, but needs would vary. For example, one may want to filter the search only to users that are members of a specific group.

Add config option for TLS ciphers

I'm trying to authenticate against a legacy LDAPS server and get "dh key too small" errors when using TLS. The LDAP server supports stronger ciphers, but Python's SSL library appears to negotiate the weaker ones, which it then rejects.

$ nmap --script ssl-enum-ciphers ldap.example.com
|   TLSv1.0:
|     ciphers:
|       TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA - E
|       TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA (dh 768) - E
|       TLS_DHE_RSA_WITH_AES_128_CBC_SHA (dh 768) - C
|       TLS_DHE_RSA_WITH_DES_CBC_SHA (dh 768) - E
|       TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA - F
|       TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 - F
|       TLS_DH_anon_WITH_3DES_EDE_CBC_SHA - F
|       TLS_DH_anon_WITH_AES_128_CBC_SHA - F
|       TLS_DH_anon_WITH_DES_CBC_SHA - F
|       TLS_DH_anon_WITH_RC4_128_MD5 - F
|       TLS_RSA_EXPORT_WITH_DES40_CBC_SHA - E
|       TLS_RSA_EXPORT_WITH_RC4_40_MD5 - E
|       TLS_RSA_WITH_3DES_EDE_CBC_SHA (rsa 2048) - C
|       TLS_RSA_WITH_AES_128_CBC_SHA (rsa 2048) - A
|       TLS_RSA_WITH_DES_CBC_SHA (rsa 2048) - C
|       TLS_RSA_WITH_NULL_MD5 (rsa 2048) - F
|       TLS_RSA_WITH_NULL_SHA (rsa 2048) - F
|       TLS_RSA_WITH_RC4_128_MD5 (rsa 2048) - C
|       TLS_RSA_WITH_RC4_128_SHA (rsa 2048) - C

I noticed ldap3 lets you set ciphers in the Tls class constructor, and the problem goes away when I modify ldap3/core/tls.py to hardcode a non-weak cipher (AES128-SHA). It would be nice if there was a config option for this.

LDAP3 error

I tried adding django-python3-ldap to one of my Django projects. The project runs and displays the login page, but I get the following error when I try logging in with my credentials:

File "...\env\lib\site-packages\django_python3_ldap\ldap.py", line 162, in authenticate
return c.get_user(**kwargs)
File "...\AppData\Local\Continuum\Anaconda3\lib\contextlib.py", line 78, in exit
raise RuntimeError("generator didn't stop after throw()")

Running Django in debug mode, I can see the local variables within ldap.py's authenticate function at line 137 of ldap.py:

  • auto_bind = 'NO_TLS'
  • c = Connection(server=Server(host='HOSTNAME', port=389, use_ssl=False, allowed_referral_hosts=[('*', True)], get_info='NO_INFO'), user='DOMAIN\USERNAME', 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=False, fast_decoder=TrueFalse)
  • ex = LDAPSocketOpenError('invalid server address',)
  • kwargs = {'username': 'USERNAME'}
  • password = PASSWORD
  • username = 'DOMAIN\USERNAME'

where the italics are replaced with my real Active Directory and user credentials. I can run the same ldap command without Django just from Python 3.5 and get an error "TrueFalse" is not defined from the bolded section above. If I change that to just "True", the connection is bind-able.

Is this a problem in django-python3-ldap or in the ldap library? I can't even see where the fast_decorder=TrueFalse comes from, but believe this is the reason for my LDAP authentication fails when trying to sign into my Django app.

Issues logging in to Active Directory server

I get this error when trying to login to /admin/

Traceback (most recent call last):
  File "/Users/levy/Code/innri/venv/lib/python3.5/site-packages/django/core/handlers/exception.py", line 41, in inner
    response = get_response(request)
  File "/Users/levy/Code/innri/venv/lib/python3.5/site-packages/django/core/handlers/base.py", line 187, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/Users/levy/Code/innri/venv/lib/python3.5/site-packages/django/core/handlers/base.py", line 185, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/Users/levy/Code/innri/venv/lib/python3.5/site-packages/django/views/decorators/cache.py", line 57, in _wrapped_view_func
    response = view_func(request, *args, **kwargs)
  File "/Users/levy/Code/innri/venv/lib/python3.5/site-packages/django/contrib/admin/sites.py", line 393, in login
    return LoginView.as_view(**defaults)(request)
  File "/Users/levy/Code/innri/venv/lib/python3.5/site-packages/django/views/generic/base.py", line 68, in view
    return self.dispatch(request, *args, **kwargs)
  File "/Users/levy/Code/innri/venv/lib/python3.5/site-packages/django/utils/decorators.py", line 67, in _wrapper
    return bound_func(*args, **kwargs)
  File "/Users/levy/Code/innri/venv/lib/python3.5/site-packages/django/views/decorators/debug.py", line 76, in sensitive_post_parameters_wrapper
    return view(request, *args, **kwargs)
  File "/Users/levy/Code/innri/venv/lib/python3.5/site-packages/django/utils/decorators.py", line 63, in bound_func
    return func.__get__(self, type(self))(*args2, **kwargs2)
  File "/Users/levy/Code/innri/venv/lib/python3.5/site-packages/django/utils/decorators.py", line 67, in _wrapper
    return bound_func(*args, **kwargs)
  File "/Users/levy/Code/innri/venv/lib/python3.5/site-packages/django/utils/decorators.py", line 149, in _wrapped_view
    response = view_func(request, *args, **kwargs)
  File "/Users/levy/Code/innri/venv/lib/python3.5/site-packages/django/utils/decorators.py", line 63, in bound_func
    return func.__get__(self, type(self))(*args2, **kwargs2)
  File "/Users/levy/Code/innri/venv/lib/python3.5/site-packages/django/utils/decorators.py", line 67, in _wrapper
    return bound_func(*args, **kwargs)
  File "/Users/levy/Code/innri/venv/lib/python3.5/site-packages/django/views/decorators/cache.py", line 57, in _wrapped_view_func
    response = view_func(request, *args, **kwargs)
  File "/Users/levy/Code/innri/venv/lib/python3.5/site-packages/django/utils/decorators.py", line 63, in bound_func
    return func.__get__(self, type(self))(*args2, **kwargs2)
  File "/Users/levy/Code/innri/venv/lib/python3.5/site-packages/django/contrib/auth/views.py", line 90, in dispatch
    return super(LoginView, self).dispatch(request, *args, **kwargs)
  File "/Users/levy/Code/innri/venv/lib/python3.5/site-packages/django/views/generic/base.py", line 88, in dispatch
    return handler(request, *args, **kwargs)
  File "/Users/levy/Code/innri/venv/lib/python3.5/site-packages/django/views/generic/edit.py", line 182, in post
    if form.is_valid():
  File "/Users/levy/Code/innri/venv/lib/python3.5/site-packages/django/forms/forms.py", line 183, in is_valid
    return self.is_bound and not self.errors
  File "/Users/levy/Code/innri/venv/lib/python3.5/site-packages/django/forms/forms.py", line 175, in errors
    self.full_clean()
  File "/Users/levy/Code/innri/venv/lib/python3.5/site-packages/django/forms/forms.py", line 385, in full_clean
    self._clean_form()
  File "/Users/levy/Code/innri/venv/lib/python3.5/site-packages/django/forms/forms.py", line 412, in _clean_form
    cleaned_data = self.clean()
  File "/Users/levy/Code/innri/venv/lib/python3.5/site-packages/django/contrib/auth/forms.py", line 187, in clean
    self.user_cache = authenticate(self.request, username=username, password=password)
  File "/Users/levy/Code/innri/venv/lib/python3.5/site-packages/django/contrib/auth/__init__.py", line 100, in authenticate
    user = backend.authenticate(*args, **credentials)
  File "/Users/levy/Code/innri/venv/lib/python3.5/site-packages/django_python3_ldap/auth.py", line 23, in authenticate
    return ldap.authenticate(*args, **kwargs)
TypeError: authenticate() takes 0 positional arguments but 1 was given

settings.py:

...
AUTHENTICATION_BACKENDS = ("django_python3_ldap.auth.LDAPBackend",)
# The URL of the LDAP server.
LDAP_AUTH_URL = "ldap://myip:389"

# Initiate TLS on connection.
#LDAP_AUTH_USE_TLS = False

# The LDAP search base for looking up users.
LDAP_AUTH_SEARCH_BASE = "dc=ruv,dc=is"

# The LDAP class that represents a user.
#LDAP_AUTH_OBJECT_CLASS = "organizationalPerson"

# User model fields mapped to the LDAP
# attributes that represent them.
LDAP_AUTH_USER_FIELDS = {
    'username': 'sAMAccountName',
    'email': 'mail'
}

LDAP_AUTH_CONNECTION_USERNAME = '[email protected]'
LDAP_AUTH_CONNECTION_PASSWORD = 'mypass'

LDAP_AUTH_SEARCH_BASE = "dc=mydc1,dc=mydc2"
LDAP_AUTH_FORMAT_USERNAME = "django_python3_ldap.utils.format_username_active_directory"

Update for compatibility with ldap3 2.x release

This project depends on ldap3 (https://pypi.python.org/pypi/ldap3) - version 2 of which was released on 27th Oct 2016. This incorporates the following warning:

In version 2 of ldap3 some default values have been changed and the ldap3 namespace has been decluttered, removing redundant constants (look at the changelog for details). Also, the result code constants were moved to ldap3.core.results and the ldap3 custom exceptions were stored in ldap3.core.exceptions. If you experience errors in your existing code you should rearrange the import statements or explicitly set the defaults to their former values.

I believe that this means that django-python3-ldap won't work with ldap3>=2.0 - it would be great if it was updated to take advantage of the latest version!

calls to ldap.connection(username=..., password=...) are restrictive

edit: a solution to this is to just override LDAP_AUTH_FORMAT_USERNAME but I wonder if a change to how we map these values would just be a more general and applicable solution?

Hey @etianen!

Thank you for all the work you have done on this library. I encountered an issue today when setting it up. The command ldap_sync_users calls ldap.connection(username=... making it so if you have a username Django field that has a different label than username it will produce an error in utils.py L#38 when it tries to pop username from the LDAP_AUTH_USER_FIELDS and it doesn't find the key username.

In my instance my username is defined as university_username in my Django Model

I am trying to think of how this could be generalized, it would require that we either accept a command line argument that represents the username field in our model with the default fallback being username or we look into LDAP_AUTH_USER_FIELDS and take they keyword from there. The problem is I am not sure how we can always know which field would link to username, because what if the user model was based on email as the username or another field.

I guess the issue here is authenticating to ldap with a username and password correlates to the LDAP_AUTH_USER_FIELDS and it probably shouldn't have that dependency.

I think maybe the best thing to do would be provide an additional setting that you can apply that maps the ldap username to the model field

---

Clarification as I have learned more about django-python3-ldap

Suppose a Django custom user model:

class User(AbstractBaseUser, PermissionsMixin):
    USERNAME_FIELD = 'email'

    email = models.EmailField(unique=True)
    university_username = models.CharField(
        verbose_name="Username",
        max_length=255,
        unique=True,
    )

Then the following mappings would apply:

LDAP_AUTH_USER_LOOKUP_FIELDS = ("email",)
LDAP_AUTH_USER_FIELDS = {
    "email": "mail",
    "university_username": "uid"
}

So pretty standard except instead of username we have university_username, here is where the problems start to occur.

# ldap_sync_users.py

class Command(BaseCommand):

    help = "Creates local user models for all users found in the remote LDAP authentication server."

    @transaction.atomic()
    def handle(self, *args, **kwargs):
        verbosity = int(kwargs.get("verbosity", 1))
        # passing in kwarg dict with key username NOT university_username
        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,
                    ))

This causes issues when we are trying to later pop and map the fields in utils.py

def convert_model_fields_to_ldap_fields(model_fields):
    """
    Converts a set of model fields into a set of corresponding
    LDAP fields.
    """
    print "convert_model", model_fields
    print settings.LDAP_AUTH_USER_FIELDS
    return {
        # field_name will get 'username' when the dict contains 'university_username', KeyError results
        settings.LDAP_AUTH_USER_FIELDS[field_name]: field_value
        for field_name, field_value
        in model_fields.items()
    }

Now assuming for sake of argument we modify the ldap_sync_users.py with this hack so we get past this issue

@transaction.atomic()
    def handle(self, *args, **kwargs):
        verbosity = int(kwargs.get("verbosity", 1))
        # we simply assign university_username to kwarg so that it matches appropriately and can move on
        with ldap.connection(university_username=settings.LDAP_AUTH_CONNECTION_USERNAME, password=settings.LDAP_AUTH_CONNECTION_PASSWORD) as connection:

Everything should work fine now. The question is can we generalize so that if you change the username field in your model it will pass in the appropriate kwarg in the command?

ldap_sync_users completes successfully, still can't login

I was running into authentication issues, so I ran the tests against my config and got the following result

Creating test database for alias 'default'...
..FF..F..F..F....E.F
======================================================================
ERROR: testRepeatedUserAuthenticationDoestRecreateUsers (django_python3_ldap.tests.TestLdap)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "D:\Usher\SourceTree\webapps\webapps\django_python3_ldap\tests.py", line 128, in testRepeatedUserAuthenticationDoestRecreateUsers
    self.assertEqual(user_1.pk, user_2.pk)
AttributeError: 'NoneType' object has no attribute 'pk'

======================================================================
FAIL: testAuthenticateUserSuccess (django_python3_ldap.tests.TestLdap)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "D:\Usher\SourceTree\webapps\webapps\django_python3_ldap\tests.py", line 101, in testAuthenticateUserSuccess
    self.assertIsInstance(user, User)
AssertionError: None is not an instance of <class 'django.contrib.auth.models.User'>

======================================================================
FAIL: testAuthenticateWithTLS (django_python3_ldap.tests.TestLdap)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "D:\Usher\SourceTree\webapps\webapps\django_python3_ldap\tests.py", line 136, in testAuthenticateWithTLS
    self.assertIsInstance(user, User)
AssertionError: None is not an instance of <class 'django.contrib.auth.models.User'>

======================================================================
FAIL: testGetUserArgsSuccess (django_python3_ldap.tests.TestLdap)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "D:\Usher\SourceTree\webapps\webapps\django_python3_ldap\tests.py", line 40, in testGetUserArgsSuccess
    self.assertIsInstance(user, User)
AssertionError: None is not an instance of <class 'django.contrib.auth.models.User'>

======================================================================
FAIL: testGetUserKwargsSuccess (django_python3_ldap.tests.TestLdap)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "D:\Usher\SourceTree\webapps\webapps\django_python3_ldap\tests.py", line 63, in testGetUserKwargsSuccess
    self.assertIsInstance(user, User)
AssertionError: None is not an instance of <class 'django.contrib.auth.models.User'>

======================================================================
FAIL: testLazySettingsClassLookup (django_python3_ldap.tests.TestLdap)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "D:\Usher\SourceTree\webapps\webapps\django_python3_ldap\tests.py", line 31, in testLazySettingsClassLookup
    self.assertEqual(settings.__class__.LDAP_AUTH_TEST_USER_USERNAME.default, "")
AssertionError: 'testuser' != ''
- testuser
+


======================================================================
FAIL: testSyncUsersCreatesUsers (django_python3_ldap.tests.TestLdap)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "D:\Usher\SourceTree\webapps\webapps\django_python3_ldap\tests.py", line 143, in testSyncUsersCreatesUsers
    self.assertGreater(User.objects.count(), 0)
AssertionError: 0 not greater than 0

----------------------------------------------------------------------
Ran 20 tests in 0.323s

FAILED (failures=6, errors=1)
Destroying test database for alias 'default'...

User binding failed

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('[email protected]','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

Certificate validation

Hi,

Certificate validation is rather simple :

import ssl  # standard library
import certifi  # new dependency

tls = ldap3.Tls(validate=ssl.CERT_REQUIRED, ca_certs_path=certifi.where())  # optionally: version=ssl.PROTOCOL_TLSv1_2
server = ldap3.Server(settings.LDAP_AUTH_URL, tls=tls)
ldap3.Connection(server, user=username, password=password, auto_bind=auto_bind) as c:

I guess it requires a few settings to be flexible.

There's something I don't understand: auto_bind is forced to AUTO_BIND_NONE in anonymous mode (eg when running ldap_sync_users), even with LDAP_AUTH_USE_TLS=True

Thanks !

ldap_sync_users completes successfully, still can't login

Hi there! Thanks for developing this.

I'm able to run ldap_sync_users and get the accounts that I expect. After doing so, I manually set is_staff and is_superuser to True for my own account and tried to login to the admin interface. All I get is the standard "Please enter the correct username and password for a staff account. Note that both fields may be case-sensitive."

I'm at a loss for where to start debugging. Can you suggest something, even a function I can monkey-patch and debug?

Exclude imports from settings.py

Dear, etianen!

I found a strange issue.
In our project there is a two settings files:

  • settings.py - test settings for development purposes
  • prod_settings.py - production settings

In the top of prod_settings we have an import line

from .settings import *

This code is failed because of necessity to import functions from this application:

LDAP_AUTH_CLEAN_USER_DATA = django_python3_ldap.utils.clean_user_data
import django_python3_ldap.utils

Traceback at the end of this letter.

So, I want to ask you: can we get rid of those imports?
For example we can switch them to import-strings. Something like this:

# settings.py
LDAP_AUTH_CLEAN_USER_DATA = 'django_python3_ldap.utils.clean_user_data'

# ldap.py _get_or_create_user
from django.utils.module_loading import import_string
user_fields = import_string(settings.LDAP_AUTH_CLEAN_USER_DATA)

I will be glad to do that, if you ask me to.
Thanks!

Traceback example

Traceback (most recent call last):
  File "/home/mnach/src/internal/manage.py", line 10, in <module>
    execute_from_command_line(sys.argv)
  File "/home/mnach/src/internal/env-3.4.3/lib/python3.4/site-packages/django/core/management/__init__.py", line 338, in execute_from_command_line
    utility.execute()
  File "/home/mnach/src/internal/env-3.4.3/lib/python3.4/site-packages/django/core/management/__init__.py", line 330, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/home/mnach/src/internal/env-3.4.3/lib/python3.4/site-packages/django/core/management/__init__.py", line 190, in fetch_command
    klass = load_command_class(app_name, subcommand)
  File "/home/mnach/src/internal/env-3.4.3/lib/python3.4/site-packages/django/core/management/__init__.py", line 40, in load_command_class
    module = import_module('%s.management.commands.%s' % (app_name, name))
  File "/usr/local/python/3.4.3/lib/python3.4/importlib/__init__.py", line 109, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 2254, in _gcd_import
  File "<frozen importlib._bootstrap>", line 2237, in _find_and_load
  File "<frozen importlib._bootstrap>", line 2226, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 1200, in _load_unlocked
  File "<frozen importlib._bootstrap>", line 1129, in _exec
  File "<frozen importlib._bootstrap>", line 1471, in exec_module
  File "<frozen importlib._bootstrap>", line 321, in _call_with_frames_removed
  File "/home/mnach/src/internal/env-3.4.3/lib/python3.4/site-packages/django/core/management/commands/runserver.py", line 14, in <module>
    from django.db.migrations.executor import MigrationExecutor
  File "/home/mnach/src/internal/env-3.4.3/lib/python3.4/site-packages/django/db/migrations/executor.py", line 6, in <module>
    from .loader import MigrationLoader
  File "/home/mnach/src/internal/env-3.4.3/lib/python3.4/site-packages/django/db/migrations/loader.py", line 10, in <module>
    from django.db.migrations.recorder import MigrationRecorder
  File "/home/mnach/src/internal/env-3.4.3/lib/python3.4/site-packages/django/db/migrations/recorder.py", line 9, in <module>
    class MigrationRecorder(object):
  File "/home/mnach/src/internal/env-3.4.3/lib/python3.4/site-packages/django/db/migrations/recorder.py", line 23, in MigrationRecorder
    class Migration(models.Model):
  File "/home/mnach/src/internal/env-3.4.3/lib/python3.4/site-packages/django/db/migrations/recorder.py", line 24, in Migration
    app = models.CharField(max_length=255)
  File "/home/mnach/src/internal/env-3.4.3/lib/python3.4/site-packages/django/db/models/fields/__init__.py", line 1081, in __init__
    super(CharField, self).__init__(*args, **kwargs)
  File "/home/mnach/src/internal/env-3.4.3/lib/python3.4/site-packages/django/db/models/fields/__init__.py", line 161, in __init__
    self.db_tablespace = db_tablespace or settings.DEFAULT_INDEX_TABLESPACE
  File "/home/mnach/src/internal/env-3.4.3/lib/python3.4/site-packages/django/conf/__init__.py", line 48, in __getattr__
    self._setup(name)
  File "/home/mnach/src/internal/env-3.4.3/lib/python3.4/site-packages/django/conf/__init__.py", line 44, in _setup
    self._wrapped = Settings(settings_module)
  File "/home/mnach/src/internal/env-3.4.3/lib/python3.4/site-packages/django/conf/__init__.py", line 92, in __init__
    mod = importlib.import_module(self.SETTINGS_MODULE)
  File "/usr/local/python/3.4.3/lib/python3.4/importlib/__init__.py", line 109, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "/home/mnach/src/internal/internal/prod_settings.py", line 4, in <module>
    from .settings import *
  File "/home/mnach/src/internal/internal/settings.py", line 221, in <module>
    import django_python3_ldap.utils
  File "/home/mnach/src/internal/django_python3_ldap/utils.py", line 12, in <module>
    from django.contrib.auth.hashers import make_password
  File "/home/mnach/src/internal/env-3.4.3/lib/python3.4/site-packages/django/contrib/auth/__init__.py", line 7, in <module>
    from django.middleware.csrf import rotate_token
  File "/home/mnach/src/internal/env-3.4.3/lib/python3.4/site-packages/django/middleware/csrf.py", line 14, in <module>
    from django.utils.cache import patch_vary_headers
  File "/home/mnach/src/internal/env-3.4.3/lib/python3.4/site-packages/django/utils/cache.py", line 26, in <module>
    from django.core.cache import caches
  File "/home/mnach/src/internal/env-3.4.3/lib/python3.4/site-packages/django/core/cache/__init__.py", line 34, in <module>
    if DEFAULT_CACHE_ALIAS not in settings.CACHES:
  File "/home/mnach/src/internal/env-3.4.3/lib/python3.4/site-packages/django/conf/__init__.py", line 48, in __getattr__
    self._setup(name)
  File "/home/mnach/src/internal/env-3.4.3/lib/python3.4/site-packages/django/conf/__init__.py", line 44, in _setup
    self._wrapped = Settings(settings_module)
  File "/home/mnach/src/internal/env-3.4.3/lib/python3.4/site-packages/django/conf/__init__.py", line 113, in __init__
    raise ImproperlyConfigured("The SECRET_KEY setting must not be empty.")
django.core.exceptions.ImproperlyConfigured: The SECRET_KEY setting must not be empty.```

use of ldap

Hello, im new to this django and ldap stuff.. after trying hard and failed to install django-ldap for python 3 on my windows os, i found this i hope "savior".
Pretty easy it installed with no problems using pip install,
after it said done i included on installed apps.

My problem is i don't know how to configure the settings, since im not too familiar with them appart from the ldap server's url.

Im running django 1.7, any advice on settings?
Also i found some example of LDAP backend authentications using django-ldap, will they work with this module?
Thanks very much in advance and hope for your answer.

base.py:577: RemovedInDjango110Warning: NoArgsCommand class is deprecated

Hi,

I just configured my settings.py as following :

LDAP_AUTH_URL = 'ldap://ldap-icd.app.myLDAP.com:389'

LDAP_AUTH_SEARCH_BASE = "dc=Internal,dc=Users,dc=root"

LDAP_AUTH_OBJECT_CLASS = "*"

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_openldap"

LDAP_AUTH_CONNECTION_USERNAME = None
LDAP_AUTH_CONNECTION_PASSWORD = None

And when I call it from my command line : py manage.py ldap_sync_users
I got the following error :

C:\Python27\lib\site-packages\django\core\management\base.py:577: RemovedInDjang o110Warning: NoArgsCommand class is deprecated and will be removed in Django 1.1 0. Use BaseCommand instead, which takes no arguments by default. RemovedInDjango110Warning

Do you have any idea why I'm facing this issue?
Thanks

Format user: {username}@{domain}

Maybe you add this code.
In my case, he helped.

def format_username_active_directory_dog(model_fields):
    username = model_fields["username"]
    if settings.LDAP_AUTH_ACTIVE_DIRECTORY_DOMAIN:
        username = "{username}@{domain}".format(
            domain=settings.LDAP_AUTH_ACTIVE_DIRECTORY_DOMAIN,
            username=username,
        )
    return username

Exception Type: ImportError Exception Value: No module named 'django_python3_ldap.auth'

Request Method: POST
Request URL: http://laisydev.slnet.bov.lc:8483/parcelmanager/authenticatedLogin/
Django Version: 1.8
Exception Type: ImportError
Exception Value:

No module named 'django_python3_ldap.auth'

Exception Location: /usr/lib/python3.5/importlib/init.py in import_module, line 126
Python Executable: /home/goslnet.gov.lc/yfevrier/git/laisy/venv/laisyvenv/bin/python3.5
Python Version: 3.5.2
Python Path:

['/home/goslnet.gov.lc/yfevrier/git/laisy',
'/usr/lib/python3.5',
'/usr/lib/python3.5/plat-x86_64-linux-gnu',
'/usr/lib/python3.5/lib-dynload',
'/home/goslnet.gov.lc/yfevrier/git/laisy/venv/laisyvenv/lib/python3.5/site-packages',
'/usr/lib/python35.zip']

Server time: Fri, 13 Jan 2017 09:01:04 -0600

Request Method: POST
Request URL: http://laisydev.slnet.bov.lc:8483/parcelmanager/authenticatedLogin/

Django Version: 1.8
Python Version: 3.5.2
Installed Applications:
('django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django_python3_ldap',
'crispy_forms',
'django_tables2',
'captcha',
'nocaptcha_recaptcha',
'parcelmanager',
'surveyplanmanager')
Installed Middleware:
('django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django.middleware.security.SecurityMiddleware')

Traceback:
File "/srv/laisy/venv/laisyvenv/lib/python3.5/site-packages/django/core/handlers/base.py" in get_response
132. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/goslnet.gov.lc/yfevrier/git/laisy/parcelmanager/views.py" in authenticatedLogin
131. user = authenticate(username=username, password=password)
File "/srv/laisy/venv/laisyvenv/lib/python3.5/site-packages/django/contrib/auth/init.py" in authenticate
66. for backend, backend_path in _get_backends(return_tuples=True):
File "/srv/laisy/venv/laisyvenv/lib/python3.5/site-packages/django/contrib/auth/init.py" in _get_backends
27. backend = load_backend(backend_path)
File "/srv/laisy/venv/laisyvenv/lib/python3.5/site-packages/django/contrib/auth/init.py" in load_backend
21. return import_string(path)()
File "/srv/laisy/venv/laisyvenv/lib/python3.5/site-packages/django/utils/module_loading.py" in import_string
26. module = import_module(module_path)
File "/usr/lib/python3.5/importlib/init.py" in import_module
126. return _bootstrap._gcd_import(name[level:], package, level)

Exception Type: ImportError at /parcelmanager/authenticatedLogin/
Exception Value: No module named 'django_python3_ldap.auth'

Python2 retrocompatibility ?

Hi !

Just tested your module with python 2.7.
Apart from classes that have to inherit from object, there does not appear to have too many things to fix to support python2.7.

Is that feasable ?

That would allow for a seamless upgrade from py2 to py3 for your users, and avoiding yet another dependency (django-auth-ldap, with its dependency on python-ldap) ..

Thanks !

LDAP_AUTH_FORMAT_USERNAME = lambda x: x['username']

It took one hour to figure this out, so I will leave it here for a documentation enhancement proposal.

Maybe other people will have to this

LDAP_AUTH_CONNECTION_USERNAME = 'cn=admin,dc=example,dc=com'
LDAP_AUTH_FORMAT_USERNAME = lambda x: x['username']
LDAP_AUTH_SEARCH_BASE = 'ou=users,dc=example,dc=com'

I don't know enough about LDAP and related protocols, but in my case I had to provide a quick fix to the login credentials in the Django settings file.

If I didn't done the right adjustment, please someone tell me.

Failover to local accounts?

Is there any way to use local Django username/password details if the LDAP login fails?

I'd like to have some standard admin and management logins regardless of the LDAP server being used.

ldap==0.9.8.2 not found

When installing using pip, the install fails with error:

(harava_env)securejava@debian:~/projects/harava$ pip install django-python3-ldap
Collecting django-python3-ldap
  Downloading django-python3-ldap-0.9.3.tar.gz
Requirement already satisfied (use --upgrade to upgrade): django>=1.7 in /home/securejava/projects/harava_env/lib/python3.4/site-packages (from django-python3-ldap)
Collecting ldap3==0.9.8.2 (from django-python3-ldap)
  Could not find a version that satisfies the requirement ldap3==0.9.8.2 (from django-python3-ldap) (from versions: 0.9.8.2.post1, 0.9.8.3, 0.9.8.3.post1, 0.9.8.4)
No matching distribution found for ldap3==0.9.8.2 (from django-python3-ldap)
(harava_env)securejava@debian:~/projects/harava$ pip install ldap3pip --version
Collecting ldap3pip
  Could not find a version that satisfies the requirement ldap3pip (from versions: )
No matching distribution found for ldap3pip
(harava_env)securejava@debian:~/projects/harava$ pip --version
pip 7.0.3 from /home/securejava/projects/harava_env/lib/python3.4/site-packages (python 3.4)

The pip version I'm using is 7.0.3.

Authenticate with a field that is not set as the custom User model's USERNAME_FIELD

Hello @etianen,

I have a custom User model like this:

class User(AbstractBaseUser, PermissionsMixin):
    identifier = models.UUIDField(default=uuid.uuid4, unique=True)
    email = models.EmailField(max_length=255, unique=True, null=True)

    USERNAME_FIELD = 'identifier'

I want to authenticate to ldap using the 'email' field instead of the 'identifier' field which is set in USERNAME_FIELD. I do not want to change USERNAME_FIELD because other authentication backends will use the 'identifier' field for authentication. By looking in the code, it seems that I have to manipulate the resolve_user_identifier function to do this. So, do you think that an LDAP_AUTH_RESOLVE_USER_IDENTIFIER setting for passing a custom callable similar to LDAP_AUTH_CLEAN_USER_DATA is a good idea? Or is there another way?

Successful Login Throws: KeyError: 'attributes'

I am getting a KeyError in ldap.py on a successful login in the dictionary user_data:

INFO:ldap3:ldap3 library initialized - logging emitted with loglevel set to DEBUG - available detail levels are: OFF, ERROR, BASIC, PROTOCOL, NETWORK, EXTENDED - sensitive data will be hidden
ERROR:django.request:Internal Server Error: /autnenticate/
Traceback (most recent call last):
  File "/websites/rnt/venv/lib/python3.5/site-packages/django/core/handlers/base.py", line 149, in get_response
    response = self.process_exception_by_middleware(e, request)
  File "/websites/rnt/venv/lib/python3.5/site-packages/django/core/handlers/base.py", line 147, in get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/websites/rnt/home/views.py", line 43, in autnenticate
    userauth = authenticate(username=_ad_user, password=_ad_pass)
  File "/websites/rnt/venv/lib/python3.5/site-packages/django/contrib/auth/__init__.py", line 74, in authenticate
    user = backend.authenticate(**credentials)
  File "/websites/rnt/venv/lib/python3.5/site-packages/django_python3_ldap/auth.py", line 23, in authenticate
    return ldap.authenticate(*args, **kwargs)
  File "/websites/rnt/venv/lib/python3.5/site-packages/django_python3_ldap/ldap.py", line 157, in authenticate
    return c.get_user(**kwargs)
  File "/websites/rnt/venv/lib/python3.5/site-packages/django_python3_ldap/ldap.py", line 101, in get_user
    return self._get_or_create_user(self._connection.response[0])
  File "/websites/rnt/venv/lib/python3.5/site-packages/django_python3_ldap/ldap.py", line 41, in _get_or_create_user
    attributes = user_data["attributes"]
KeyError: 'attributes'

user_data:

INFO:ldap3:ldap3 library initialized - logging emitted with loglevel set to DEBUG - available detail levels are: OFF, ERROR, BASIC, PROTOCOL, NETWORK, EXTENDED - sensitive data will be hidden
INFO:root:<class 'dict'>
INFO:root:['__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'clear', 'copy', 'fromkeys', 'get', 'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values']
INFO:root:{'uri': ["b'ldaps://ForestDnsZones.domain.com/DC=ForestDnsZones,DC=domain,DC=com'"], 'type': 'searchResRef'}

The full configuration:

AUTHENTICATION_BACKENDS = (
        'django_python3_ldap.auth.LDAPBackend',
)
LDAP_AUTH_URL = "ldaps://domain.com"
LDAP_AUTH_USE_TLS = True
LDAP_AUTH_SEARCH_BASE = "dc=domain,dc=com"
LDAP_AUTH_OBJECT_CLASS = "userClass"
LDAP_AUTH_USER_FIELDS = {
    "username": "sAMAccountName",
    "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 = "DOMAIN"
LDAP_AUTH_CONNECTION_USERNAME = 'user'
LDAP_AUTH_CONNECTION_PASSWORD = 'pass'
LOGGING = {
    "version": 1,
    "disable_existing_loggers": False,
    "loggers": {
        "django_python3_ldap": {
            "level": "DEBUG",
        },
    },
}

Login fails silently on insufficient read permissions

The login fails silently when the bound user doesn't have permission to read the attributes of the bound user object during login.

The OpenLDAP logs show a 32 error code when this occurs. I haven't checked whether the response from the OpenLDAP sever includes the error code, though:

 SEARCH RESULT tag=101 err=32 nentries=0 text=

It would be useful for django-python3-ldap to log a warning when this occurs (e.g., similar to the one for invalid credentials), as the error likely signals a configuration problem.

Part of the code for version 9.14 is not in the - pypi.python.org

If the settings specify an alternative username and password for querying, rebind as that.

if (
    (settings.LDAP_AUTH_CONNECTION_USERNAME or settings.LDAP_AUTH_CONNECTION_PASSWORD) and
    (
        settings.LDAP_AUTH_CONNECTION_USERNAME != username or
        settings.LDAP_AUTH_CONNECTION_PASSWORD != password
    )
):
    try:
        c.rebind(
            user=format_username({"username": settings.LDAP_AUTH_CONNECTION_USERNAME}),
            password=settings.LDAP_AUTH_CONNECTION_PASSWORD,
        )
    except LDAPException as ex:
        logger.info("LDAP rebind failed: {ex}".format(ex=ex))
        yield None
        return

pip looking for wrong python3-ldap version

Hi,

I'm having an issue installing through pip. It's looking for python3-ldap version 0.9.5.3, which doesn't seem to exist (pip install python3-ldap==0.9.5.3 fails for me as well). Is there any way to use a different python3-ldap version?

Downloading/unpacking python3-ldap==0.9.5.3 (from django-python3-ldap)
  Could not find a version that satisfies the requirement python3-ldap==0.9.5.3 (from django-python3-ldap) (from versions: 0.9.3.5, 0.9.4.2, 0.9.5.4, 0.9.6.2, 0.9.7, 0.8.3, 0.9.1, 0.9.2.2, 0.9.3.5, 0.
9.4.2, 0.9.5.4, 0.9.6.2, 0.9.7)
Cleaning up...

Thanks!

LDAP connect failed: invalid server address

firas@MAChINE1-2-1:~/platform$ ./manage.py ldap_sync_users
LDAP connect failed: invalid server address
INFO:django_python3_ldap.ldap:LDAP connect failed: invalid server address
Traceback (most recent call last):
  File "./manage.py", line 116, in <module>
    execute_from_command_line([sys.argv[0]] + django_args)
  File "/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 354, in execute_from_command_line
    utility.execute()
  File "/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 346, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/local/lib/python2.7/site-packages/django/core/management/base.py", line 394, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/local/lib/python2.7/site-packages/django/core/management/base.py", line 445, in execute
    output = self.handle(*args, **options)
  File "/local/lib/python2.7/site-packages/django/utils/decorators.py", line 145, in inner
    return func(*args, **kwargs)
  File "/local/lib/python2.7/site-packages/django_python3_ldap/management/commands/ldap_sync_users.py", line 22, in handle
    user=user,
  File "/usr/lib/python2.7/contextlib.py", line 36, in __exit__
    raise RuntimeError("generator didn't stop after throw()")
RuntimeError: generator didn't stop after throw()

Exception Type: ImportError Exception Value: No module named 'django_python3_ldap.auth'

Environment:

Request Method: POST
Request URL: http://laisydev.slnet.bov.lc:8483/parcelmanager/authenticatedLogin/

Django Version: 1.8
Python Version: 3.5.2
Installed Applications:
('django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django_python3_ldap',
'crispy_forms',
'django_tables2',
'captcha',
'nocaptcha_recaptcha',
'parcelmanager',
'surveyplanmanager')
Installed Middleware:
('django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django.middleware.security.SecurityMiddleware')

Traceback:
File "/srv/laisy/venv/laisyvenv/lib/python3.5/site-packages/django/core/handlers/base.py" in get_response
132. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/goslnet.gov.lc/yfevrier/git/laisy/parcelmanager/views.py" in authenticatedLogin
131. user = authenticate(username=username, password=password)
File "/srv/laisy/venv/laisyvenv/lib/python3.5/site-packages/django/contrib/auth/init.py" in authenticate
66. for backend, backend_path in _get_backends(return_tuples=True):
File "/srv/laisy/venv/laisyvenv/lib/python3.5/site-packages/django/contrib/auth/init.py" in _get_backends
27. backend = load_backend(backend_path)
File "/srv/laisy/venv/laisyvenv/lib/python3.5/site-packages/django/contrib/auth/init.py" in load_backend
21. return import_string(path)()
File "/srv/laisy/venv/laisyvenv/lib/python3.5/site-packages/django/utils/module_loading.py" in import_string
26. module = import_module(module_path)
File "/usr/lib/python3.5/importlib/init.py" in import_module
126. return _bootstrap._gcd_import(name[level:], package, level)

Exception Type: ImportError at /parcelmanager/authenticatedLogin/
Exception Value: No module named 'django_python3_ldap.auth'

compatibility django 1.11

hey,

the changes introduced by this ticket raises some errors with the auth.py/ldap.py. The request parameter is now populated down to the authenticate() function => *args now contains now the request:
https://code.djangoproject.com/ticket/25187

I think the function signature mismatch between the ldap.py authenticate() and auth.py authenticate() causes the problems.

Sync Groups

Hello!

I'm a Django newbie, but managed to install and use this LDAP Auth, synced all the users in a breeze! Thanks! :) I was wondering if it is possible to sync the LDAP groups also. We are running an old version of OpenLDAP where the membership is in the group attributes and NOT on the user's.

Thanks!

Multiple LDAP servers?

Is there a way to use a iterable of servers and make multiple attempts to connect to each? For example:

LDAP_AUTH_URL = ("ldap://0.0.0.1:389", "ldap://0.0.0.2:389", ldap://0.0.0.3:398",)

module 'ldap3' has no attribute 'SEARCH_SCOPE_WHOLE_SUBTREE'

I'm getting the error below. This is a new setup. I'm very new to Django so it's very possible I'm doing something wrong. The error occurs during login. I did a packet capture and I can see that the auth is binding properly, so I would say this error happens after ldap binding.

Using:
Python 3.5.3
Django 1.10.6
ldap3 2.2.1
django-python3-ldap 0.9.11

Traceback (most recent call last):
  File "C:\Users\jeff\django-ccp\lib\site-packages\django_python3_ldap\ldap.py", line 137, in connection
    yield Connection(c)
  File "C:\Users\jeff\django-ccp\lib\site-packages\django_python3_ldap\ldap.py", line 162, in authenticate
    return c.get_user(**kwargs)
  File "C:\Users\jeff\django-ccp\lib\site-packages\django_python3_ldap\ldap.py", line 101, in get_user
    search_scope = ldap3.SEARCH_SCOPE_WHOLE_SUBTREE,
AttributeError: module 'ldap3' has no attribute 'SEARCH_SCOPE_WHOLE_SUBTREE'

Here are my settings:

LDAP_AUTH_URL = "ldap://ip.addr:389"

LDAP_AUTH_USE_TLS = False

LDAP_AUTH_SEARCH_BASE = "MY-OU-PATH"

LDAP_AUTH_OBJECT_CLASS = "person"

LDAP_AUTH_USER_FIELDS = {
    'username': 'sAMAccountName',
    'first_name': 'givenName',
    'last_name': 'sn',
    'email': 'mail',
}

LDAP_AUTH_USER_LOOKUP_FIELDS = ("username",)

LDAP_AUTH_ACTIVE_DIRECTORY_DOMAIN = "corp"

LDAP_AUTH_FORMAT_USERNAME = "django_python3_ldap.utils.format_username_active_directory"

Option for ObjectCategory

In my place sometimes adding (objectCategory=person) to the search filter helps limiting the scope to 'person' objects only and hence improving the performance of the search query. I just wonder if we could have an optional SETTING entry for it, similar to ObjectClass.

Thanks.

Issue with the admin interface

Hi, first, I would like to thank you for your nice work. It's a pain in the .. to work with LDAP.

I just follow your instructions and your configuration like this :

AUTHENTICATION_BACKENDS = (
    'django_python3_ldap.auth.LDAPBackend'
)
LDAP_AUTH_URL = 'ldap://ldap-icd.app.my-ldap.com:389'
LDAP_AUTH_USE_TLS = False
LDAP_AUTH_SEARCH_BASE = "dc=Internal,dc=Users,dc=root"
LDAP_AUTH_OBJECT_CLASS = "person"
LDAP_AUTH_USER_FIELDS = {
     "username": "uid",
}

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_openldap"
LDAP_AUTH_CONNECTION_USERNAME = "uid=reader.myAPP,dc=Services,dc=Users,dc=root"
LDAP_AUTH_CONNECTION_PASSWORD = "myPass"

When I execute python manage.py ldap_sync_users it's okay, all the username appears on the screen but when I try to logging through the administration interface, it's not working. My error message :

Please enter a correct username and password. Note that both fields are case-sensitive

I'm sure that both username and password are correct.

Any idea? Thanks

Problem with ldap_sync_users command (need ldap3 v2.2.3 module)

Hello,
Thanks for your clear documentation :)
I try to make working your module for the first time but I have some issue.

My LDAP server is particular and need the last stable version (2.2.3) of ldap3 python module.
You can see the issue corrected 2 days ago here : cannatag/ldap3#334

When I try to import ldap users in django with your module, it's not working.

You can see my try here :

gduale:~:$ . ./py361-test/bin/activate
(py361-test) gduale:~:$ pip install django-python3-ldap
Collecting django-python3-ldap
  Using cached django-python3-ldap-0.9.14.tar.gz
Collecting django>=1.8 (from django-python3-ldap)
  Using cached Django-1.11-py2.py3-none-any.whl
Collecting ldap3==2.2.0 (from django-python3-ldap)
  Using cached ldap3-2.2.0-py2.py3-none-any.whl
Collecting pytz (from django>=1.8->django-python3-ldap)
  Using cached pytz-2017.2-py2.py3-none-any.whl
Collecting pyasn1>=0.1.8 (from ldap3==2.2.0->django-python3-ldap)
  Using cached pyasn1-0.2.3-py2.py3-none-any.whl
Installing collected packages: pytz, django, pyasn1, ldap3, django-python3-ldap
  Running setup.py install for django-python3-ldap ... done
Successfully installed django-1.11 django-python3-ldap-0.9.14 ldap3-2.2.0 pyasn1-0.2.3 pytz-2017.2

Then I know that with ldap3 version 2.2.0 it will not work (I already try), so I install the latest version :

(py361-test) gduale:~:$ pip install --upgrade ldap3
Collecting ldap3
  Using cached ldap3-2.2.3-py2.py3-none-any.whl
Requirement already up-to-date: pyasn1>=0.1.8 in ./py361-test/lib/python3.6/site-packages (from ldap3)
Installing collected packages: ldap3
  Found existing installation: ldap3 2.2.0
    Uninstalling ldap3-2.2.0:
      Successfully uninstalled ldap3-2.2.0
Successfully installed ldap3-2.2.3

Then I try to sync the users, but it fails :

(py361-test) gduale:~/django-projects/test-c2i/c2i:$ python manage.py ldap_sync_users
Traceback (most recent call last):
  File "manage.py", line 22, in <module>
    execute_from_command_line(sys.argv)
  File "/home/gduale/py361-test/lib/python3.6/site-packages/django/core/management/__init__.py", line 363, in execute_from_command_line
    utility.execute()
  File "/home/gduale/py361-test/lib/python3.6/site-packages/django/core/management/__init__.py", line 355, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/home/gduale/py361-test/lib/python3.6/site-packages/django/core/management/base.py", line 283, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/home/gduale/py361-test/lib/python3.6/site-packages/django/core/management/base.py", line 330, in execute
    output = self.handle(*args, **options)
  File "/home/gduale/make_python/python-3.6.1/lib/python3.6/contextlib.py", line 53, in inner
    return func(*args, **kwds)
  File "/home/gduale/py361-test/lib/python3.6/site-packages/django_python3_ldap/management/commands/ldap_sync_users.py", line 21, in handle
    for user in connection.iter_users():
  File "/home/gduale/py361-test/lib/python3.6/site-packages/django_python3_ldap/ldap.py", line 90, in <genexpr>
    if entry["type"] == "searchResEntry"
  File "/home/gduale/py361-test/lib/python3.6/site-packages/django_python3_ldap/ldap.py", line 66, in _get_or_create_user
    **user_lookup
  File "/home/gduale/py361-test/lib/python3.6/site-packages/django/db/models/manager.py", line 85, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/home/gduale/py361-test/lib/python3.6/site-packages/django/db/models/query.py", line 475, in update_or_create
    lookup, params = self._extract_model_params(defaults, **kwargs)
  File "/home/gduale/py361-test/lib/python3.6/site-packages/django/db/models/query.py", line 531, in _extract_model_params
    "', '".join(sorted(invalid_params)),
django.core.exceptions.FieldError: Invalid field name(s) for model User: 'd', 'i', 'u'.

Do you know if is it possible to make working your module with the latest stable version of ldap3 please ?
Thank you,
Best regards.

'module' object has no attribute 'LDAPBindError'

After provisioning a new VM with my app and dumping the DB from my dev db to it, I tried to login with the superuser account 'admin' that would have been setup by the provisioning script. It failed with this error
'module' object has no attribute 'LDAPBindError'

I realized my mistake was that the superuser would have the password from the dev db since I overwrote the new db completely. Logging in with that password works.

My test VM CANNOT connect to the LDAP server right now, so I fully expected an error about failure to connect. But from the looks of this, the exception handling isn't getting that far.

The issue is that the error isn't saying the password was wrong, or that the connection can't be made. It's saying the module doesn't have an attribute that the connection object should have to even tell which exception to throw. And I don't know why.

My setup has the builtin ModelBackend being checked before LDAP. So the correct superuser pw will avoid ever hitting the LDAP check, and therefore the error.

AUTHENTICATION_BACKENDS = [
    'django.contrib.auth.backends.ModelBackend',
    'django_python3_ldap.auth.LDAPBackend',
]

But with the wrong password, the check is passed on to the next backend, django_python3_ldap, which fails to throw the correct exception.

Django Version:	1.10.4
Exception Type:	AttributeError
Exception Value:	
'module' object has no attribute 'LDAPBindError'
Exception Location:	/srv/api/lib/python3.4/site-packages/django_python3_ldap/ldap.py in connection, line 138
Python Executable:	/srv/api/bin/uwsgi
Python Version:	3.4.2
Python Path:	
['/srv/api/',
 '.',
 '',
 '/srv/api/lib/python3.4',
 '/srv/api/lib/python3.4/plat-x86_64-linux-gnu',
 '/srv/api/lib/python3.4/lib-dynload',
 '/usr/lib/python3.4',
 '/usr/lib/python3.4/plat-x86_64-linux-gnu',
 '/srv/api/lib/python3.4/site-packages']

Force auto_bind to be AUTO_BIND_NONE

In ldap.py, There's a bit of code that forces the use of auto_bind if user_identifier is present. (Which it will be given it's called in the authenticate method, where the username/email/id must always be given, and this is passed through to connection). I'm encountering a server that will not let me connect unless auto_bind=AUTO_BIND_NONE. Is there a workaround for this issue?

if user_identifier:
        if settings.LDAP_AUTH_USE_TLS:
            auto_bind = ldap3.AUTO_BIND_TLS_BEFORE_BIND
        else:
            auto_bind = ldap3.AUTO_BIND_NO_TLS
    else:
        auto_bind = ldap3.AUTO_BIND_NONE

can't map ldap3 search to django-python3-ldap config

hi

1st things 1st: thank you for sharing this codebase with the community!

I can't seem to find the right configuration for the django plugin though, I have a working ldap3 example and trying to match it in my settings but always getting

LDAP connect failed: LDAPInvalidCredentialsResult - 49 - invalidCredentials - None - 80090308: LdapErr: DSID-0C0903A8, comment: AcceptSecurityContext error, data 52e, v1db1 - bindResponse - None

the following is a working example of search I'm doing with ldap3

from ldap3 import Server, Connection, ALL

print('### SERVER')
server = Server('host.group.domain.com', get_info=ALL)

print('### CONNECT')
conn = Connection(
    server,
    'CN=ldap_user,OU=SERVICE,OU=100 Common Services Objects,OU=Common Services and Applications,DC=group,DC=domain,DC=com',
    'ldap_password',
    auto_bind=True)

print('### SEARCH')
conn.search('DC=group,DC=domain,DC=com', '(&(sAMAccountName=username_search)(objectclass=user))')

print('### ENTRIES')
print([e for e in conn.entries])

I tried, among other combinations, the following

LDAP_AUTH_URL = 'ldap://host.group.domain.com:389'

LDAP_AUTH_SEARCH_BASE = 'DC=group,DC=domain,DC=com'

LDAP_AUTH_USER_FIELDS = {
    'username': 'sAMAccountName',
    'first_name': 'givenName',
    'last_name': 'sn',
    'email': 'mail'
}

LDAP_AUTH_CONNECTION_USERNAME = 'CN=ldap_user,OU=SERVICE,OU=100 Common Services Objects,OU=Common Services and Applications,DC=group,DC=domain,DC=com'
LDAP_AUTH_CONNECTION_PASSWORD = 'ldap_password'

LDAP_AUTH_FORMAT_USERNAME = "django_python3_ldap.utils.format_username_active_directory"

but always getting the invalid credential error. could you give a quick hint please? I'd be happy to help writing a bit of documentation if this use case is relevant for you

many thanks!

KeyError: 'attributes' on ldap_sync_users

I'm trying to sync all my active directory users to my local django users, all attempts has been unsuccessful, the command gives me a KeyError: 'attributes' on attributes = user_data["attributes"]. Also the login doesn't work.
I'm using Django 1.8.6 with Python 3.4, here's my ldap settings:

LDAP_AUTH_URL = "ldaps://10.0.0.1:636"
LDAP_AUTH_USE_TLS = None
LDAP_AUTH_SEARCH_BASE = "DC=mydomain,DC=example,DC=com"
LDAP_AUTH_OBJECT_CLASS = "organizationalPerson"
LDAP_AUTH_USER_FIELDS = {
    "username": "sAMAccountName",
    "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_CONNECTION_USERNAME =   'CN=admin,OU=Users,OU=MyGroup,OU=MyDomain,DC=mydomain,DC=example,DC=com'

LDAP_AUTH_CONNECTION_PASSWORD = 'f4ncyp4ssw0rd'

AUTHENTICATION_BACKENDS = (
    'django_python3_ldap.auth.LDAPBackend',
    'django.contrib.auth.backends.ModelBackend',
)

I modified the ldap.py module printint the value of user_data and gives me this output:

{'uri': ["b'ldaps://mydomain.example.com/CN=Configuration,DC=mydomain,DC=example,DC=com'"], 'type': 'searchResRef'}

So, the dictionary cames without the attributes value, what I am missing? Configuration error?

PS: Sorry by me terrible english ;)

Question - Not sure how to map LDAP_AUTH settings

I have a silly question. I seem to keep getting LDAP login failed: automatic bind not successful - invalidCredentials error and I believe it has to do with wrong settings. I am having trouble mapping the settings. I used another app that used LDAP to authenticate (these settings worked). How would I translate the settings below, to use django-python3-ldap?

uri=ldap://chop.edu:3268
user_filter=objectClass=*
user_name_attr=sAMAccountName
bind_user=cn=Version Control,ou=AdminUsers,ou=Res,dc=research,dc=chop,dc=edu
bind_password=removed-password
basedn=dc=chop,dc=edu
search_scope=SUBTREE

I am currently using:

LDAP_AUTH_URL='ldap://chop.edu:3268'
LDAP_AUTH_CONNECTION_USERNAME='cn=Version Control,ou=AdminUsers,ou=Res,dc=research,dc=chop,dc=edu'
LDAP_AUTH_CONNECTION_PASSWORD='removed-password'
LDAP_AUTH_USE_TLS=False
LDAP_AUTH_SEARCH_BASE='dc=chop,dc=edu'
LDAP_AUTH_OBJECT_CLASS='objectClass=*'
LDAP_AUTH_USER_LOOKUP_FIELDS = ("username",)
LDAP_AUTH_SYNC_USER_RELATIONS = 'django_python3_ldap.utils.sync_user_relations'
LDAP_AUTH_USER_FIELDS = {
    "username": "sAMAccountName",
    "first_name": "givenName",
    "last_name": "sn",
    "email": "mail",
}

On successful bind user details not saved in a local Django User model and user not logged in

Hi,

I've just created a fresh Django project with all default settings (default user model etc.) to test this.

I've installed django-python3-ldap as described, added 'django_python3_ldap' my INSTALLED_APPS and set AUTHENTICATION_BACKENDS = ['django_python3_ldap.auth.LDAPBackend'].

The rest of the settings I've overridden are:

LDAP_AUTH_URL = "[my server URL]"
LDAP_AUTH_SEARCH_BASE = "dc=[1st DC],dc=[2nd DC],dc=[3rd DC],dc=[4th DC]"
LDAP_AUTH_FORMAT_USERNAME = "django_python3_ldap.utils.format_username_active_directory"

LOGGING = {
"version": 1,
"disable_existing_loggers": False,
"handlers": {
"console": {
"class": "logging.StreamHandler",
},
},
"loggers": {
"django_python3_ldap": {
"handlers": ["console"],
"level": "DEBUG",
},
},
}

I used a python shell to test binding as follows:

from ldap3 import Server, Connection
s = Server('[Server URL]', get_info=ALL)
c = Connection(s, user='[username]', password='[right password]')
if not c.bind():
print("Error!", c.result)
else:
print("It Worked!", c.result)

It Worked! {'description': 'success', 'referrals': None, etc....}

c = Connection(s, user='[username]', password='[wrong password]')
if not c.bind():
print("Error!", c.result)
else:
print("It Worked!", c.result)

Error! {'description': 'invalidCredentials', 'referrals': None, etc....}

So now I'm trying to use this to log in to my django site. At first I was just trying to log into the admin site using this, but now I've built a proper login form in the front-end site just to check that this all works and it wasn't the admin login page doing something funky.

When I attempt to log in using an incorrect User & Pass, in my console I see:

[17/Mar/2017 12:56:27] "POST /accounts/login/ HTTP/1.1" 200 1135
LDAP login failed: automatic bind not successful - invalidCredentials

but when I use the correct User & Pass I only get:
[17/Mar/2017 12:56:27] "POST /accounts/login/ HTTP/1.1" 200 1135

The login page still says "Incorrect username and / or password! Please double-check and try again." and doesn't forward me on to the correct place, and there are no new user entries in my auth_user table in my DB.

Any idea's where I'm going wrong? It appears I have enough settings right for it to recognise bad credentials, but not enough right for it to do anything useful on a successful bind!

Any help appreciated!

Many thanks,
-Tim

Multiple search base support?

First thanks for making this app available, its great. I've been looking at the code to see how I would implement multiple search bases? Would I have to create a custom backend subclassing a lot of the django_python3_ldap code for each search base like this in my settings.py:

AUTHENTICATION_BACKENDS = ('my_custom_auth.auth.UKLDAPBackend', 'my_custom_auth.auth.DELDAPBackend', 'django.contrib.auth.backends.ModelBackend')

Referencing different search bases e.g.

LDAP_AUTH_UK_SEARCH_BASE = 'ou=engineering,ou=united kingdom,ou=my company users,dc=my company,dc=global,dc=corp' LDAP_AUTH_DE_SEARCH_BASE = 'ou=engineering,ou=germany,ou=my company users,dc=my company,dc=global,dc=corp'

Or is there something already built in that would support multiple search bases? I can't see something immediately obvious but I may well have missed it.

_get_or_create_user: user_data["attributes"] - key error

ldap search can return different kinds of responses:

  • type searchResEntry - it contains the attributes key, all good
  • type searchResRef - attributes key is not present, and then _get_or_create_user will raise an error.

It's especially valid for iter_users when both types can be present.

Quick workaround for iter_users:

return (
    self._get_or_create_user(entry)
    for entry
    in paged_entries if entry["type"] == "searchResEntry"
)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.