diff --git a/docs/installation/ldap.md b/docs/installation/ldap.md new file mode 100644 index 000000000..5a90ec5e3 --- /dev/null +++ b/docs/installation/ldap.md @@ -0,0 +1,101 @@ +This guide explains how to implement LDAP authentication using an external server. User authentication will fall back to +built-in Django users in the event of a failure. + +# Requirements + +## Install openldap-devel + +On Ubuntu: + +``` +sudo apt-get install -y python-dev libldap2-dev libsasl2-dev libssl-dev +``` + +On CentOS: + +``` +sudo yum install -y python-devel openldap-devel +``` + +## Install django-auth-ldap + +``` +sudo pip install django-auth-ldap +``` + +# Configuration + +Create a file in the same directory as `configuration.py` (typically `netbox/netbox/`) named `ldap_config.py`. Define all of the parameters required below in `ldap_config.py`. + +## General Server Configuration + +```python +import ldap + +# Server URI +AUTH_LDAP_SERVER_URI = "ldaps://ad.example.com" + +# The following may be needed if you are binding to Active Directory. +AUTH_LDAP_CONNECTION_OPTIONS = { + ldap.OPT_REFERRALS: 0 +} + +# Set the DN and password for the NetBox service account. +AUTH_LDAP_BIND_DN = "CN=NETBOXSA, OU=Service Accounts,DC=example,DC=com" +AUTH_LDAP_BIND_PASSWORD = "demo" + +# Include this setting if you want to ignore certificate errors. This might be needed to accept a self-signed cert. +# Note that this is a NetBox-specific setting which sets: +# ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER) +LDAP_IGNORE_CERT_ERRORS = True +``` + +## User Authentication + +```python +from django_auth_ldap.config import LDAPSearch + +# This search matches users with the sAMAccountName equal to the provided username. This is required if the user's +# username is not in their DN (Active Directory). +AUTH_LDAP_USER_SEARCH = LDAPSearch("ou=Users,dc=example,dc=com", + ldap.SCOPE_SUBTREE, + "(sAMAccountName=%(user)s)") + +# If a user's DN is producible from their username, we don't need to search. +AUTH_LDAP_USER_DN_TEMPLATE = "uid=%(user)s,ou=users,dc=example,dc=com" + +# You can map user attributes to Django attributes as so. +AUTH_LDAP_USER_ATTR_MAP = { + "first_name": "givenName", + "last_name": "sn" +} +``` + +# User Groups for Permissions + +```python +from django_auth_ldap.config import LDAPSearch, GroupOfNamesType + +# This search ought to return all groups to which the user belongs. django_auth_ldap uses this to determine group +# heirarchy. +AUTH_LDAP_GROUP_SEARCH = LDAPSearch("dc=example,dc=com", ldap.SCOPE_SUBTREE, + "(objectClass=group)") +AUTH_LDAP_GROUP_TYPE = GroupOfNamesType() + +# Define a group required to login. +AUTH_LDAP_REQUIRE_GROUP = "CN=NETBOX_USERS,DC=example,DC=com" + +# Define special user types using groups. Exercise great caution when assigning superuser status. +AUTH_LDAP_USER_FLAGS_BY_GROUP = { + "is_active": "cn=active,ou=groups,dc=example,dc=com", + "is_staff": "cn=staff,ou=groups,dc=example,dc=com", + "is_superuser": "cn=superuser,ou=groups,dc=example,dc=com" +} + +# For more granular permissions, we can map LDAP groups to Django groups. +AUTH_LDAP_FIND_GROUP_PERMS = True + +# Cache groups for one hour to reduce LDAP traffic +AUTH_LDAP_CACHE_GROUPS = True +AUTH_LDAP_GROUP_CACHE_TIMEOUT = 3600 +``` diff --git a/docs/ldap.md b/docs/ldap.md deleted file mode 100644 index dc1130ca5..000000000 --- a/docs/ldap.md +++ /dev/null @@ -1,123 +0,0 @@ - -

LDAP Authentication

- -This section details configuration of alternatives to standard django authentication, specifically LDAP and Active Directory. - -[TOC] - -# Requirements - -**Install openldap-devel** - -On Ubuntu: -``` -sudo apt-get install -y python-dev libldap2-dev libsasl2-dev libssl-dev -``` -or on CentOS: -``` -sudo yum install -y python-devel openldap-devel -``` - -**Install django-auth-ldap** -``` -sudo pip install django-auth-ldap -``` - -# General Configuration -In this guide, all shown configuration ought to be appended to the `settings.py` file. - -# Basic Setup -The following configuration adds the LDAP Authentication backend to your netbox site: -```python -AUTHENTICATION_BACKENDS = ( - 'django_auth_ldap.backend.LDAPBackend', - 'django.contrib.auth.backends.ModelBackend', -) -``` - -# General Server Configuration -```python -# Set the server -AUTH_LDAP_SERVER_URI = "ldaps://ad.example.com" - -# The following may be needed if you are binding to active directory -import ldap -AUTH_LDAP_CONNECTION_OPTIONS = { - ldap.OPT_REFERRALS: 0 -} - -# Set the DN and password for the netbox service account -AUTH_LDAP_BIND_DN = "CN=NETBOXSA, OU=Service Accounts,DC=example,DC=com" -AUTH_LDAP_BIND_PASSWORD = "demo" -``` - -# User Authentication -```python -from django_auth_ldap.config import LDAPSearch -# Search for a users DN. - -# This search matches users with the sAMAccountName equal to the inputed username. -# This is required if the user's username is not in their DN. (Active Directory) -AUTH_LDAP_USER_SEARCH = LDAPSearch("ou=Users,dc=example,dc=com", - ldap.SCOPE_SUBTREE, - "(sAMAccountName=%(user)s)") - -# If a users dn is producable from their username, we don't need to search -AUTH_LDAP_USER_DN_TEMPLATE = "uid=%(user)s,ou=users,dc=example,dc=com" - -# You can map user attributes to django attributes as so. -AUTH_LDAP_USER_ATTR_MAP = { - "first_name": "givenName", - "last_name": "sn" -} -``` - -# User Groups for permissions -```python -from django_auth_ldap.config import LDAPSearch, GroupOfNamesType - -# This search ought to return all groups that a user may be part of. -# django_auth_ldap uses this to determine group heirarchy -AUTH_LDAP_GROUP_SEARCH = LDAPSearch("dc=example,dc=com", ldap.SCOPE_SUBTREE, - "(objectClass=group)") -AUTH_LDAP_GROUP_TYPE = GroupOfNamesType() - -# Define a group required to login -AUTH_LDAP_REQUIRE_GROUP = "CN=NETBOX_USERS,DC=example,DC=com" - -# Define user type using groups -AUTH_LDAP_USER_FLAGS_BY_GROUP = { - "is_active": "cn=active,ou=groups,dc=example,dc=com", - "is_staff": "cn=staff,ou=groups,dc=example,dc=com", - "is_superuser": "cn=superuser,ou=groups,dc=example,dc=com" -} - -# For more granular permissions, we can map ldap groups to django groups -AUTH_LDAP_FIND_GROUP_PERMS = True - -# Cache groups for one hour to reduce ldap traffic -AUTH_LDAP_CACHE_GROUPS = True -AUTH_LDAP_GROUP_CACHE_TIMEOUT = 3600 -``` - -# Certificate Checking -```python -# If your certificate is valid and trusted, you probably don't need to do anything -# Otherwise, see the solutions below: - -# Don't check the ldap server's certificate as much -ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_ALLOW) - -# Don't check the cert at all -ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER) -``` - -# Logging -If authentication isn't working, you can add the following to your `settings.py`. -```python -import logging - -logger = logging.getLogger('django_auth_ldap') -logger.addHandler(logging.StreamHandler()) -logger.setLevel(logging.DEBUG) -``` diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index 273ed3ab4..301e29510 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -1,3 +1,4 @@ +import logging import os import socket @@ -39,6 +40,34 @@ DATETIME_FORMAT = getattr(configuration, 'DATETIME_FORMAT', 'N j, Y g:i a') SHORT_DATETIME_FORMAT = getattr(configuration, 'SHORT_DATETIME_FORMAT', 'Y-m-d H:i') CSRF_TRUSTED_ORIGINS = ALLOWED_HOSTS +# Attempt to import LDAP configuration if it has been defined +LDAP_IGNORE_CERT_ERRORS = False +try: + from ldap_config import * + LDAP_CONFIGURED = True +except ImportError: + LDAP_CONFIGURED = False + +# LDAP configuration (optional) +if LDAP_CONFIGURED: + try: + import ldap, django_auth_ldap + # Prepend LDAPBackend to the default ModelBackend + AUTHENTICATION_BACKENDS = [ + 'django_auth_ldap.backend.LDAPBackend', + 'django.contrib.auth.backends.ModelBackend', + ] + # Optionally disable strict certificate checking + if LDAP_IGNORE_CERT_ERRORS: + ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER) + # Enable logging for django_auth_ldap + logger = logging.getLogger('django_auth_ldap') + logger.addHandler(logging.StreamHandler()) + logger.setLevel(logging.DEBUG) + except ImportError: + raise ImproperlyConfigured("LDAP authentication has been configured, but django-auth-ldap is not installed. " + "You can remove netbox/ldap.py to disable LDAP.") + BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # Database