Change ldap_config.py integration to allow for Multiple LDAP sources #998

Closed
opened 2025-12-29 16:27:41 +01:00 by adam · 4 comments
Owner

Originally created by @Chipa001 on GitHub (May 30, 2017).

Could the structure in ldap_config.py and settings.py be changed so that Multiple LDAP sources are possible?

Example doco: https://pythonhosted.org/django-auth-ldap/multiconfig.html

We have an Active Directory system that works fine, but we also have an external trust to another AD. The LDAP configuration currently doesn't allow lookups to the external AD correctly, even using LDAPSearchUnion
From my investigation doing direct lookups against each LDAP source is the best method to work around this.

Originally created by @Chipa001 on GitHub (May 30, 2017). Could the structure in ldap_config.py and settings.py be changed so that Multiple LDAP sources are possible? Example doco: [https://pythonhosted.org/django-auth-ldap/multiconfig.html](https://pythonhosted.org/django-auth-ldap/multiconfig.html) We have an Active Directory system that works fine, but we also have an external trust to another AD. The LDAP configuration currently doesn't allow lookups to the external AD correctly, even using LDAPSearchUnion From my investigation doing direct lookups against each LDAP source is the best method to work around this.
adam closed this issue 2025-12-29 16:27:42 +01:00
Author
Owner

@rthill commented on GitHub (Jun 21, 2017):

I did have the same issue on a Django project several years ago. What I did was using the django-auth-ldap module and I created an LDAP configuration like the following:

import ldap
from django_auth_ldap.config import LDAPSearch, GroupOfNamesType, ActiveDirectoryGroupType
#
### ACTIVE DIRECTORY AUTH SETTINGS
#
AUTH_LDAP_AD_BASE_DN = "dc=domain1,dc=com"
AUTH_LDAP_AD_SERVER_URI = "ldap://172.16.1.1:389 ldap://172.16.1.2:389"
AUTH_LDAP_AD_BIND_DN = "cn=django,OU=Internal,%s" % AUTH_LDAP_AD_BASE_DN
AUTH_LDAP_AD_BIND_PASSWORD = "xxx"
AUTH_LDAP_AD_USER_SEARCH = LDAPSearch(
    "ou=internal,%s" % AUTH_LDAP_AD_BASE_DN,
    ldap.SCOPE_SUBTREE,
    "(saMAccountName=%(user)s)"
)
AUTH_LDAP_AD_GROUP_SEARCH = LDAPSearch(
    "ou=internal,%s" % AUTH_LDAP_AD_BASE_DN,
    ldap.SCOPE_SUBTREE,
    "(objectClass=group)"
)
AUTH_LDAP_AD_GROUP_TYPE = GroupOfNamesType(name_attr="cn")
AUTH_LDAP_AD_REQUIRE_GROUP = "CN=Grp1,OU=Groups,OU=Internal,%s" % AUTH_LDAP_AD_BASE_DN
AUTH_LDAP_AD_USER_ATTR_MAP = {
    "first_name": "givenName",
    "last_name": "sn",
    "email": "mail"
}
AUTH_LDAP_AD_USER_FLAGS_BY_GROUP = {
    "is_active": "CN=Grp1,OU=Groups,OU=Internal,%s" % AUTH_LDAP_AD_BASE_DN
    "is_staff": "CN=Grp1,OU=Groups,OU=Internal,%s" % AUTH_LDAP_AD_BASE_DN
    "is_superuser": "CN=Grp1,OU=Groups,OU=Internal,%s" % AUTH_LDAP_AD_BASE_DN
}
## This is the default, but I like to be explicit.
AUTH_LDAP_AD_ALWAYS_UPDATE_USER = True
## Use LDAP group membership to calculate group permissions.
AUTH_LDAP_AD_FIND_GROUP_PERMS = True
## Cache group memberships for an hour to minimize LDAP traffic
AUTH_LDAP_AD_CACHE_GROUPS = True
AUTH_LDAP_AD_GROUP_CACHE_TIMEOUT = 3600

#
### OPENLDAP AUTH SETTINGS
#
AUTH_LDAP_LOCAL_BASE_DN = "dc=domain2,dc=com"
AUTH_LDAP_LOCAL_SERVER_URI = "ldaps://localhost:636"
AUTH_LDAP_LOCAL_BIND_DN = "uid=ldapadmin,%s" % AUTH_LDAP_LOCAL_BASE_DN
AUTH_LDAP_LOCAL_BIND_PASSWORD = "xxx"
AUTH_LDAP_LOCAL_USER_SEARCH = LDAPSearch(
    "dc=domain2,dc=com",
    ldap.SCOPE_SUBTREE,
    "(&(objectClass=inetOrgPerson)(uid=%(user)s))"
)
AUTH_LDAP_LOCAL_GROUP_SEARCH = LDAPSearch(
    "ou=groups,dc=domain2,dc=com",
    ldap.SCOPE_SUBTREE,
    "(objectClass=groupOfNames)"
)
AUTH_LDAP_LOCAL_GROUP_TYPE = ActiveDirectoryGroupType()
AUTH_LDAP_LOCAL_MIRROR_GROUPS = True
# Fill local django user_auth table with User information
AUTH_LDAP_LOCAL_USER_ATTR_MAP = {
    "first_name": "givenName",
    "last_name": "sn",
    "email": "mail",
}
# Extend DB information with data from LDAP
AUTH_LDAP_LOCAL_PROFILE_ATTR_MAP = {
    "base_dn": "baseDn",
    "customer_name": "o",
}

AUTH_LDAP_LOCAL_USER_FLAGS_BY_GROUP = {}
## This is the default, but I like to be explicit.
AUTH_LDAP_LOCAL_ALWAYS_UPDATE_USER = True
## Use LDAP group membership to calculate group permissions.
AUTH_LDAP_LOCAL_FIND_GROUP_PERMS = True
## Cache group memberships for an hour to minimize LDAP traffic
AUTH_LDAP_LOCAL_CACHE_GROUPS = True
AUTH_LDAP_LOCAL_GROUP_CACHE_TIMEOUT = 3600

This configuration is imported into the main settings!

To make the primary and secondary work you need to create a router:

from django_auth_ldap.backend import LDAPBackend

class LDAPBackendActiveDirectory(LDAPBackend):
    """
    This should be the first backend in the authentication backends list,
    as superusers are defined in the Active Directory
    """
    settings_prefix = "AUTH_LDAP_AD_"

class LDAPBackendLDAP(LDAPBackend):
    """
    This is the OpenLDAP to authenticate customer admins
    and/or superusers if they get defined here.
    """
    settings_prefix = "AUTH_LDAP_LOCAL_"

In the main settings file you then have to define the backends order to use:

AUTHENTICATION_BACKENDS = (
    'lib.ldapBackends.LDAPBackendActiveDirectory',
    'lib.ldapBackends.LDAPBackendLDAP',
    # Fallback authentication to local DB
    'django.contrib.auth.backends.ModelBackend',
)

I hope this code is still valid, I think I did use it on a project something like 10 years ago.

@rthill commented on GitHub (Jun 21, 2017): I did have the same issue on a Django project several years ago. What I did was using the django-auth-ldap module and I created an LDAP configuration like the following: ``` import ldap from django_auth_ldap.config import LDAPSearch, GroupOfNamesType, ActiveDirectoryGroupType # ### ACTIVE DIRECTORY AUTH SETTINGS # AUTH_LDAP_AD_BASE_DN = "dc=domain1,dc=com" AUTH_LDAP_AD_SERVER_URI = "ldap://172.16.1.1:389 ldap://172.16.1.2:389" AUTH_LDAP_AD_BIND_DN = "cn=django,OU=Internal,%s" % AUTH_LDAP_AD_BASE_DN AUTH_LDAP_AD_BIND_PASSWORD = "xxx" AUTH_LDAP_AD_USER_SEARCH = LDAPSearch( "ou=internal,%s" % AUTH_LDAP_AD_BASE_DN, ldap.SCOPE_SUBTREE, "(saMAccountName=%(user)s)" ) AUTH_LDAP_AD_GROUP_SEARCH = LDAPSearch( "ou=internal,%s" % AUTH_LDAP_AD_BASE_DN, ldap.SCOPE_SUBTREE, "(objectClass=group)" ) AUTH_LDAP_AD_GROUP_TYPE = GroupOfNamesType(name_attr="cn") AUTH_LDAP_AD_REQUIRE_GROUP = "CN=Grp1,OU=Groups,OU=Internal,%s" % AUTH_LDAP_AD_BASE_DN AUTH_LDAP_AD_USER_ATTR_MAP = { "first_name": "givenName", "last_name": "sn", "email": "mail" } AUTH_LDAP_AD_USER_FLAGS_BY_GROUP = { "is_active": "CN=Grp1,OU=Groups,OU=Internal,%s" % AUTH_LDAP_AD_BASE_DN "is_staff": "CN=Grp1,OU=Groups,OU=Internal,%s" % AUTH_LDAP_AD_BASE_DN "is_superuser": "CN=Grp1,OU=Groups,OU=Internal,%s" % AUTH_LDAP_AD_BASE_DN } ## This is the default, but I like to be explicit. AUTH_LDAP_AD_ALWAYS_UPDATE_USER = True ## Use LDAP group membership to calculate group permissions. AUTH_LDAP_AD_FIND_GROUP_PERMS = True ## Cache group memberships for an hour to minimize LDAP traffic AUTH_LDAP_AD_CACHE_GROUPS = True AUTH_LDAP_AD_GROUP_CACHE_TIMEOUT = 3600 # ### OPENLDAP AUTH SETTINGS # AUTH_LDAP_LOCAL_BASE_DN = "dc=domain2,dc=com" AUTH_LDAP_LOCAL_SERVER_URI = "ldaps://localhost:636" AUTH_LDAP_LOCAL_BIND_DN = "uid=ldapadmin,%s" % AUTH_LDAP_LOCAL_BASE_DN AUTH_LDAP_LOCAL_BIND_PASSWORD = "xxx" AUTH_LDAP_LOCAL_USER_SEARCH = LDAPSearch( "dc=domain2,dc=com", ldap.SCOPE_SUBTREE, "(&(objectClass=inetOrgPerson)(uid=%(user)s))" ) AUTH_LDAP_LOCAL_GROUP_SEARCH = LDAPSearch( "ou=groups,dc=domain2,dc=com", ldap.SCOPE_SUBTREE, "(objectClass=groupOfNames)" ) AUTH_LDAP_LOCAL_GROUP_TYPE = ActiveDirectoryGroupType() AUTH_LDAP_LOCAL_MIRROR_GROUPS = True # Fill local django user_auth table with User information AUTH_LDAP_LOCAL_USER_ATTR_MAP = { "first_name": "givenName", "last_name": "sn", "email": "mail", } # Extend DB information with data from LDAP AUTH_LDAP_LOCAL_PROFILE_ATTR_MAP = { "base_dn": "baseDn", "customer_name": "o", } AUTH_LDAP_LOCAL_USER_FLAGS_BY_GROUP = {} ## This is the default, but I like to be explicit. AUTH_LDAP_LOCAL_ALWAYS_UPDATE_USER = True ## Use LDAP group membership to calculate group permissions. AUTH_LDAP_LOCAL_FIND_GROUP_PERMS = True ## Cache group memberships for an hour to minimize LDAP traffic AUTH_LDAP_LOCAL_CACHE_GROUPS = True AUTH_LDAP_LOCAL_GROUP_CACHE_TIMEOUT = 3600 ``` This configuration is imported into the main settings! To make the primary and secondary work you need to create a router: ``` from django_auth_ldap.backend import LDAPBackend class LDAPBackendActiveDirectory(LDAPBackend): """ This should be the first backend in the authentication backends list, as superusers are defined in the Active Directory """ settings_prefix = "AUTH_LDAP_AD_" class LDAPBackendLDAP(LDAPBackend): """ This is the OpenLDAP to authenticate customer admins and/or superusers if they get defined here. """ settings_prefix = "AUTH_LDAP_LOCAL_" ``` In the main settings file you then have to define the backends order to use: ``` AUTHENTICATION_BACKENDS = ( 'lib.ldapBackends.LDAPBackendActiveDirectory', 'lib.ldapBackends.LDAPBackendLDAP', # Fallback authentication to local DB 'django.contrib.auth.backends.ModelBackend', ) ``` I hope this code is still valid, I think I did use it on a project something like 10 years ago.
Author
Owner

@Chipa001 commented on GitHub (Jun 23, 2017):

Thanks @rthill
Unfortunately this method would potentially require changing the main settings file after each upgrade. I haven't monitored changes for this file over versions, but I expect it does get changed.
I think the better aim would be to fix it so the only changes required for any LDAP method is in the user managed config file of ldap_config.py

@Chipa001 commented on GitHub (Jun 23, 2017): Thanks @rthill Unfortunately this method would potentially require changing the main settings file after each upgrade. I haven't monitored changes for this file over versions, but I expect it does get changed. I think the better aim would be to fix it so the only changes required for any LDAP method is in the user managed config file of ldap_config.py
Author
Owner

@RyanD0001 commented on GitHub (Oct 12, 2017):

Could someone tell me where I need to put ldap_config.py on the docker image?

@RyanD0001 commented on GitHub (Oct 12, 2017): Could someone tell me where I need to put ldap_config.py on the docker image?
Author
Owner

@jeremystretch commented on GitHub (Jun 25, 2019):

This has been open for over two years with no one taking it on. Closing it out.

@jeremystretch commented on GitHub (Jun 25, 2019): This has been open for over two years with no one taking it on. Closing it out.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/netbox#998