Allow Multiple LDAP Configurations #3017

Closed
opened 2025-12-29 18:24:47 +01:00 by adam · 2 comments
Owner

Originally created by @Haeki on GitHub (Nov 15, 2019).

Environment

  • Python version: 3.7.5
  • NetBox version: 2.6.7

Proposed Functionality

Change the settings.py file so that LDAP Multi Config is supported.

Add an optional config parameter LDAP_CONFIGURATIONS = [] with the default being [ldap_config]. There multiple ldap configuration files can be declared.

Import this parameter in the settings.py file:

LDAP_CONFIGS = getattr(configuration, 'LDAP_CONFIGURATIONS', ['ldap_config'])

As long as this parameter is the not set and the default is used nothing will change. If the ldap_config.py file exists it will be used and if not LDAP won't be used at all.

But if necessary you will be able to specify more than one ldap_config file.

Change the LDAP authentication section in the settings.py file:

#
# LDAP authentication (optional)
#
import importlib
for n, settingsFile in enumerate(LDAP_CONFIGURATIONS, 1):
    # Try to import a ldap_config file
    try:
        config = importlib.import_module('.' + settingsFile, 'netbox')
    except ImportError:
        continue

    if(n == 1):
        # Check that django_auth_ldap is installed
        try:
            from netbox import settings
            import ldap
            import django_auth_ldap
        except ImportError:
            raise ImproperlyConfigured(
                "LDAP authentication has been configured, but django-auth-ldap is not installed. Remove "
                "netbox/ldap_config.py to disable LDAP."
            )
    
    #Create a prefix for the backend
    prefix = "AUTH_LDAP_%d_" % n

    # Required configuration parameters
    try:
        setattr(settings, (prefix + 'SERVER_URI'), getattr(config, 'AUTH_LDAP_SERVER_URI'))
    except AttributeError:
        raise ImproperlyConfigured(
            "Required parameter AUTH_LDAP_SERVER_URI is missing from %s" % settingsFile
        )

    # Optional configuration parameters
    setattr(settings, (prefix + 'ALWAYS_UPDATE_USER'), getattr(config, 'AUTH_LDAP_ALWAYS_UPDATE_USER', True))
    setattr(settings, (prefix + 'AUTHORIZE_ALL_USERS'), getattr(config, 'AUTH_LDAP_AUTHORIZE_ALL_USERS', False))
    setattr(settings, (prefix + 'BIND_AS_AUTHENTICATING_USER'), getattr(config, 'AUTH_LDAP_BIND_AS_AUTHENTICATING_USER', False))
    setattr(settings, (prefix + 'BIND_DN'), getattr(config, 'AUTH_LDAP_BIND_DN', ''))
    setattr(settings, (prefix + 'BIND_PASSWORD'), getattr(config, 'AUTH_LDAP_BIND_PASSWORD', ''))
    setattr(settings, (prefix + 'CACHE_TIMEOUT'), getattr(config, 'AUTH_LDAP_CACHE_TIMEOUT', 0))
    setattr(settings, (prefix + 'CONNECTION_OPTIONS'), getattr(config, 'AUTH_LDAP_CONNECTION_OPTIONS', {}))
    setattr(settings, (prefix + 'DENY_GROUP'), getattr(config, 'AUTH_LDAP_DENY_GROUP', None))
    setattr(settings, (prefix + 'FIND_GROUP_PERMS'), getattr(config, 'AUTH_LDAP_FIND_GROUP_PERMS', False))
    setattr(settings, (prefix + 'GLOBAL_OPTIONS'), getattr(config, 'AUTH_LDAP_GLOBAL_OPTIONS', {}))
    setattr(settings, (prefix + 'GROUP_SEARCH'), getattr(config, 'AUTH_LDAP_GROUP_SEARCH', None))
    setattr(settings, (prefix + 'GROUP_TYPE'), getattr(config, 'AUTH_LDAP_GROUP_TYPE', None))
    setattr(settings, (prefix + 'MIRROR_GROUPS'), getattr(config, 'AUTH_LDAP_MIRROR_GROUPS', None))
    setattr(settings, (prefix + 'MIRROR_GROUPS_EXCEPT'), getattr(config, 'AUTH_LDAP_MIRROR_GROUPS_EXCEPT', None))
    setattr(settings, (prefix + 'PERMIT_EMPTY_PASSWORD'), getattr(config, 'AUTH_LDAP_PERMIT_EMPTY_PASSWORD', False))
    setattr(settings, (prefix + 'REQUIRE_GROUP'), getattr(config, 'AUTH_LDAP_REQUIRE_GROUP', None))
    setattr(settings, (prefix + 'NO_NEW_USERS'), getattr(config, 'AUTH_LDAP_NO_NEW_USERS', False))
    setattr(settings, (prefix + 'START_TLS'), getattr(config, 'AUTH_LDAP_START_TLS', False))
    setattr(settings, (prefix + 'USER_QUERY_FIELD'), getattr(config, 'AUTH_LDAP_USER_QUERY_FIELD', None))
    setattr(settings, (prefix + 'USER_ATTRLIST'), getattr(config, 'AUTH_LDAP_USER_ATTRLIST', None))
    setattr(settings, (prefix + 'USER_ATTR_MAP'), getattr(config, 'AUTH_LDAP_USER_ATTR_MAP', {}))
    setattr(settings, (prefix + 'USER_DN_TEMPLATE'), getattr(config, 'AUTH_LDAP_USER_DN_TEMPLATE', None))
    setattr(settings, (prefix + 'USER_FLAGS_BY_GROUP'), getattr(config, 'AUTH_LDAP_USER_FLAGS_BY_GROUP', {}))
    setattr(settings, (prefix + 'USER_SEARCH'), getattr(config, 'AUTH_LDAP_USER_SEARCH', None))
    
    if(n == 1):
        # Optionally disable strict certificate checking
        if getattr(config, 'LDAP_IGNORE_CERT_ERRORS', False):
            ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER)

        # Enable logging for django_auth_ldap
        ldap_logger = logging.getLogger('django_auth_ldap')
        ldap_logger.addHandler(logging.StreamHandler())
        ldap_logger.setLevel(logging.DEBUG)
    
    #Prepend LDAPBackend to the authentication backends list
    #Note that a new backend is needed for each ldap_config file
    AUTHENTICATION_BACKENDS.insert(n - 1, ('netbox.custom_backends.LDAPBackend%d' % n))

Add a custom_backend.py file were the Backends are created:

from django_auth_ldap.backend import LDAPBackend

class LDAPBackend1(LDAPBackend):
    settings_prefix = 'AUTH_LDAP_1_'

Use Case

Allows NetBox to be configured so that users from two different Domains are able to login.

Originally created by @Haeki on GitHub (Nov 15, 2019). ### Environment * Python version: 3.7.5 * NetBox version: 2.6.7 ### Proposed Functionality Change the settings.py file so that [LDAP Multi Config](https://django-auth-ldap.readthedocs.io/en/latest/multiconfig.html) is supported. Add an optional config parameter `LDAP_CONFIGURATIONS = []` with the default being `[ldap_config]`. There multiple ldap configuration files can be declared. Import this parameter in the settings.py file: ```python LDAP_CONFIGS = getattr(configuration, 'LDAP_CONFIGURATIONS', ['ldap_config']) ``` As long as this parameter is the not set and the default is used nothing will change. If the ldap_config.py file exists it will be used and if not LDAP won't be used at all. But if necessary you will be able to specify more than one ldap_config file. Change the LDAP authentication section in the settings.py file: ```python # # LDAP authentication (optional) # import importlib for n, settingsFile in enumerate(LDAP_CONFIGURATIONS, 1): # Try to import a ldap_config file try: config = importlib.import_module('.' + settingsFile, 'netbox') except ImportError: continue if(n == 1): # Check that django_auth_ldap is installed try: from netbox import settings import ldap import django_auth_ldap except ImportError: raise ImproperlyConfigured( "LDAP authentication has been configured, but django-auth-ldap is not installed. Remove " "netbox/ldap_config.py to disable LDAP." ) #Create a prefix for the backend prefix = "AUTH_LDAP_%d_" % n # Required configuration parameters try: setattr(settings, (prefix + 'SERVER_URI'), getattr(config, 'AUTH_LDAP_SERVER_URI')) except AttributeError: raise ImproperlyConfigured( "Required parameter AUTH_LDAP_SERVER_URI is missing from %s" % settingsFile ) # Optional configuration parameters setattr(settings, (prefix + 'ALWAYS_UPDATE_USER'), getattr(config, 'AUTH_LDAP_ALWAYS_UPDATE_USER', True)) setattr(settings, (prefix + 'AUTHORIZE_ALL_USERS'), getattr(config, 'AUTH_LDAP_AUTHORIZE_ALL_USERS', False)) setattr(settings, (prefix + 'BIND_AS_AUTHENTICATING_USER'), getattr(config, 'AUTH_LDAP_BIND_AS_AUTHENTICATING_USER', False)) setattr(settings, (prefix + 'BIND_DN'), getattr(config, 'AUTH_LDAP_BIND_DN', '')) setattr(settings, (prefix + 'BIND_PASSWORD'), getattr(config, 'AUTH_LDAP_BIND_PASSWORD', '')) setattr(settings, (prefix + 'CACHE_TIMEOUT'), getattr(config, 'AUTH_LDAP_CACHE_TIMEOUT', 0)) setattr(settings, (prefix + 'CONNECTION_OPTIONS'), getattr(config, 'AUTH_LDAP_CONNECTION_OPTIONS', {})) setattr(settings, (prefix + 'DENY_GROUP'), getattr(config, 'AUTH_LDAP_DENY_GROUP', None)) setattr(settings, (prefix + 'FIND_GROUP_PERMS'), getattr(config, 'AUTH_LDAP_FIND_GROUP_PERMS', False)) setattr(settings, (prefix + 'GLOBAL_OPTIONS'), getattr(config, 'AUTH_LDAP_GLOBAL_OPTIONS', {})) setattr(settings, (prefix + 'GROUP_SEARCH'), getattr(config, 'AUTH_LDAP_GROUP_SEARCH', None)) setattr(settings, (prefix + 'GROUP_TYPE'), getattr(config, 'AUTH_LDAP_GROUP_TYPE', None)) setattr(settings, (prefix + 'MIRROR_GROUPS'), getattr(config, 'AUTH_LDAP_MIRROR_GROUPS', None)) setattr(settings, (prefix + 'MIRROR_GROUPS_EXCEPT'), getattr(config, 'AUTH_LDAP_MIRROR_GROUPS_EXCEPT', None)) setattr(settings, (prefix + 'PERMIT_EMPTY_PASSWORD'), getattr(config, 'AUTH_LDAP_PERMIT_EMPTY_PASSWORD', False)) setattr(settings, (prefix + 'REQUIRE_GROUP'), getattr(config, 'AUTH_LDAP_REQUIRE_GROUP', None)) setattr(settings, (prefix + 'NO_NEW_USERS'), getattr(config, 'AUTH_LDAP_NO_NEW_USERS', False)) setattr(settings, (prefix + 'START_TLS'), getattr(config, 'AUTH_LDAP_START_TLS', False)) setattr(settings, (prefix + 'USER_QUERY_FIELD'), getattr(config, 'AUTH_LDAP_USER_QUERY_FIELD', None)) setattr(settings, (prefix + 'USER_ATTRLIST'), getattr(config, 'AUTH_LDAP_USER_ATTRLIST', None)) setattr(settings, (prefix + 'USER_ATTR_MAP'), getattr(config, 'AUTH_LDAP_USER_ATTR_MAP', {})) setattr(settings, (prefix + 'USER_DN_TEMPLATE'), getattr(config, 'AUTH_LDAP_USER_DN_TEMPLATE', None)) setattr(settings, (prefix + 'USER_FLAGS_BY_GROUP'), getattr(config, 'AUTH_LDAP_USER_FLAGS_BY_GROUP', {})) setattr(settings, (prefix + 'USER_SEARCH'), getattr(config, 'AUTH_LDAP_USER_SEARCH', None)) if(n == 1): # Optionally disable strict certificate checking if getattr(config, 'LDAP_IGNORE_CERT_ERRORS', False): ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER) # Enable logging for django_auth_ldap ldap_logger = logging.getLogger('django_auth_ldap') ldap_logger.addHandler(logging.StreamHandler()) ldap_logger.setLevel(logging.DEBUG) #Prepend LDAPBackend to the authentication backends list #Note that a new backend is needed for each ldap_config file AUTHENTICATION_BACKENDS.insert(n - 1, ('netbox.custom_backends.LDAPBackend%d' % n)) ``` Add a custom_backend.py file were the Backends are created: ```python from django_auth_ldap.backend import LDAPBackend class LDAPBackend1(LDAPBackend): settings_prefix = 'AUTH_LDAP_1_' ``` ### Use Case Allows NetBox to be configured so that users from two different Domains are able to login.
adam closed this issue 2025-12-29 18:24:47 +01:00
Author
Owner

@Haeki commented on GitHub (Nov 15, 2019):

If anyone has a better idea how to add LDAP Multi Config support i would be happy to hear it. I have implemented this change in our NetBox environment and i haven't found any problems with it. But it is really annoying to change the settings file everytime we update NetBox.

@Haeki commented on GitHub (Nov 15, 2019): If anyone has a better idea how to add LDAP Multi Config support i would be happy to hear it. I have implemented this change in our NetBox environment and i haven't found any problems with it. But it is really annoying to change the settings file everytime we update NetBox.
Author
Owner

@jeremystretch commented on GitHub (Nov 26, 2019):

FYI native support for LDAP will be removed in v2.8 and replaced with generic external authentication pass-through; please see #2328. As such I don't think it makes sense to spend any further development on the current implementation (excluding bug fixes).

@jeremystretch commented on GitHub (Nov 26, 2019): FYI native support for LDAP will be removed in v2.8 and replaced with generic external authentication pass-through; please see #2328. As such I don't think it makes sense to spend any further development on the current implementation (excluding bug fixes).
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/netbox#3017