1
votes

I am trying to login as a LDAP-user with an e-mail adress. I used the following code:

settings.py

AUTH_LDAP_SERVER_URI = "ldap://192.168.12.123"

AUTH_LDAP_BIND_DN = "User"
AUTH_LDAP_BIND_PASSWORD = "Password"
AUTH_LDAP_CONNECTION_OPTIONS = {
    ldap.OPT_DEBUG_LEVEL: 1,
    ldap.OPT_REFERRALS: 0
}

AUTH_LDAP_USER_SEARCH = LDAPSearch("DC=domain,DC=com", ldap.SCOPE_ONELEVEL, "(uid=%(user)s)")
AUTH_LDAP_GROUP_SEARCH = LDAPSearch("DC=domain,DC=com", ldap.SCOPE_SUBTREE, "(objectClass=group)")
AUTH_LDAP_GROUP_TYPE = NestedActiveDirectoryGroupType()

AUTH_LDAP_USER_ATTR_MAP = {
    "first_name": "givenName",
    "last_name": "sn",
    "email": "mail"
}

AUTH_LDAP_ALWAYS_UPDATE_USER = True

LDAP_AUTH_OBJECT_CLASS = "inetOrgPerson"

AUTH_LDAP_FIND_GROUP_PERMS = True

AUTH_LDAP_CACHE_GROUPS = True
AUTH_LDAP_GROUP_CACHE_TIMEOUT = 3600

AUTH_LDAP_E_USER_SEARCH = LDAPSearch("DC=domain,DC=com", ldap.SCOPE_SUBTREE, ldap.SCOPE_ONELEVEL, "(mail=%(user)s)")
AUTH_LDAP_E_USER_ATTR_MAP = AUTH_LDAP_USER_ATTR_MAP
AUTH_LDAP_E_ALWAYS_UPDATE_USER = AUTH_LDAP_ALWAYS_UPDATE_USER

AUTHENTICATION_BACKENDS = (
    'django_auth_ldap.backend.LDAPBackend',
    #'django.contrib.auth.backends.ModelBackend',
    'accounts.backends.LDAPEmailBackend',
)

backends.py

from django_auth_ldap.backend import LDAPBackend, _LDAPUser

class LDAPEmailBackend(LDAPBackend):
    settings_prefix = "AUTH_LDAP_E_"

    def get_or_create_user(self, email, ldap_user):

    model = self.get_user_model()
    username_field = getattr(model, 'USERNAME_FIELD', 'username')

    kwargs = {
        username_field + '__iexact': ldap_user.attrs['uid'][0],
        'defaults': {
         username_field: ldap_user.attrs['uid'][0].lower(),
         'email': email
        }
    }

    return model.objects.get_or_create(**kwargs)

The console gives me this:

search_s('DC=sbvg,DC=ch', 1, '(uid=%(user)s)') returned 0 objects: Authentication failed for [email protected]: failed to map the username to a DN. Caught LDAPError while authenticating [email protected]: SERVER_DOWN({'desc': u"Can't contact LDAP server"},)

If you have any idea, do not hesitate to post it.

3

3 Answers

0
votes

I don't know if this will be the answer,

LDAPSearch method has too many scope arguments. It require one positional argument for scope.

AUTH_LDAP_E_USER_SEARCH = LDAPSearch("DC=domain,DC=com", ldap.SCOPE_SUBTREE, ldap.SCOPE_ONELEVEL, "(mail=%(user)s)")

reference

0
votes

I successfully logged in Django after LDAP authentication using an email address instead of a username. This is what is needed.

  1. You don't need to create an additional backend. (Ex: LDAPEmailBackend in your case)

  2. Contents of settings.py should be as below

    AUTH_LDAP_USER_SEARCH = LDAPSearch("DC=domain, DC=com", ldap.SCOPE_SUBTREE, "mail=%(user)s)")
    
    AUTH_LDAP_USER_ATTR_MAP = { 
          'first_name': 'givenName',
          'last_name': 'sn',
          'email': 'mail',
    }
    
    AUTHENTICATION_BACKENDS = ( 
           'django_auth_ldap.backend.LDAPBackend',
           'django.contrib.auth.backends.ModelBackend',
    )
    

Note (some additional information):

  1. get_or_create_user() is deprecated. If at all you want to use it, use get_or_build_user().

  2. Perhaps, you will need to get rid of AUTH_LDAP_USER_DN_TEMPLATE if the dn does not contain email address (which is perhaps the reason for the server error) because AUTH_LDAP_USER_DN_TEMPLATE will look for a direct bind.

  3. Make sure that your LDAP DIT (Directory Information Tree) contains an entry of mail: what@ever in the scope of DC=domain, DC=com.
0
votes

I landed on this question while searching for ways to login to LDAP using both username and email on Django. Here's the solution I've found, based on this gist. The examples below assume that the LDAP directory has the user email address mapped to "mail". I've seen cases where it was named to something else, so make sure you're querying by the right property.

For login with email only

  1. No additional backend needed

  2. Make sure LDAP queries users by email, and that the backend searches Django users by email as well. On settings.py

AUTH_LDAP_USER_SEARCH = LDAPSearch(
    "DC=domain,DC=com",
    ldap.SCOPE_SUBTREE,
    "uid=%(user)s)"
)

AUTH_LDAP_USER_QUERY_FIELD = 'email'

For login with both username and email

  1. Create an additional backend.
# -*- coding: utf-8 -*-
"""Custom authentication backend classes
"""
from __future__ import unicode_literals

from django_auth_ldap.backend import LDAPBackend


class LDAPEmailBackend(LDAPBackend):
    settings_prefix = 'AUTH_LDAP_E_'
  1. settings.py should be as follows
# other settings

AUTHENTICATION_BACKENDS = (
    'django_auth_ldap.backend.LDAPBackend',  # this will handle LDAP login with username as usual
    'your_app.backends.LDAPEmailBackend',  # this will handle LDAP login with email
    'django.contrib.auth.backends.ModelBackend',
    # additional authentication backends
)

# LDAP search by uid
AUTH_LDAP_USER_SEARCH = LDAPSearch(
    "DC=domain,DC=com",
    ldap.SCOPE_SUBTREE,
    "uid=%(user)s)"
)

# LDAP search by mail
AUTH_LDAP_E_USER_SEARCH = LDAPSearch(
    "DC=domain,DC=com",
    ldap.SCOPE_SUBTREE,
    "mail=%(user)s)"
)
AUTH_LDAP_FILTERSTR=(uid=%(user)s)
AUTH_LDAP_E_FILTERSTR=(mail=%(user)s)
AUTH_LDAP_USER_ATTR_MAP = {
    "username": "uid",
    "email": "mail"
}
AUTH_LDAP_E_USER_ATTR_MAP = AUTH_LDAP_USER_ATTR_MAP  # we can use the same attr mapping
AUTH_LDAP_E_USER_QUERY_FIELD = "email"  # make sure it searches Django users by email

# other LDAP settings can have the same value for both backends, like _USER_ATTR_MAP above

# other settings

Tested with Django 3.1.1/Python 3.8.5 and Django 1.11.27/Python 2.7.12