Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature tls #32

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,7 @@ target/
# PyCharm project
.idea

#VS Code
.vscode

register_and_upload_new_version.bat
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,28 @@ List of LDAP server to authenticate against. 3 information are needed for each:
- the TCP port to connect on (default: 389 for non SSL and 636 for SSL)
- a boolean tag to enable or not the use of SSL during authentication process against this server.

Optional parameter.
Define a TLS object to initiate a tunnel before binding the LDAP/AD connection:
- Client certificate and key files will need to be generated and defined in the object
- AD server will need to be trusted by the client, this is usually done by exporting the domain root CA cert, coping to the client (/usr/share/ca-certificates)and importing using the "update-ca-certificates" command.
- The trusted CA list will need be defined in the object.
- add a 'tls' attribute to the LDAP_SERVERS setting, this will automatically enable the tunnel.

### tls

Example TLS object:
```python
from ldap3 import tls
tls = Tls(validate=ssl.CERT_REQUIRED, version=ssl.PROTOCOL_TLSv1_2,
ca_certs_path='/etc/ssl/certs', local_certificate_file='/etc/ssl/certs/server.crt',
local_private_key_file='/etc/ssl/private/server.key',
ca_certs_file='/etc/ssl/certs/ca-certificates.crt'
)

```

More information available in the LDAP3 [documentation](https://ldap3.readthedocs.io/en/latest/ssltls.html#)

You can define as many authentication servers as needed (as many as you have in you network) with, for each, it's own parameters.
The pool is used in the order you defined. If the first one is available, authentication is against it, if the server is not available, the next is used. In all cases, if an answer is received for a server, it's considered authoritative even if it's negative

Expand All @@ -32,12 +54,14 @@ LDAP_SERVERS = [
'port': 389,
'use_ssl': False,
'get_info': 'NONE',
'tls' : tls,
},
{
'host': '<server 2 IP>',
'port': 389,
'use_ssl': False,
'get_info': 'NONE',
'tls' : tls,
},
]
```
Expand Down
31 changes: 26 additions & 5 deletions django_auth_ldap3_ad/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,15 @@
from django.conf import settings
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group
from ldap3 import Server, ServerPool, Connection, FIRST, SYNC, SIMPLE, NTLM
from ldap3 import Server, ServerPool, Connection, FIRST, SYNC, SIMPLE, NTLM, AUTO_BIND_TLS_BEFORE_BIND, AUTO_BIND_NO_TLS
from six import string_types
from django.core.exceptions import ObjectDoesNotExist, ImproperlyConfigured
from django.utils import timezone
import logging
from django.contrib.auth.signals import user_logged_in
from django.contrib.auth.backends import ModelBackend


logger = logging.getLogger(__name__)


Expand Down Expand Up @@ -93,6 +94,9 @@ class LDAP3ADBackend(ModelBackend):
# do we use LDAP Groups?
use_groups = False

# is tls set?
tls_bool = False

def init_and_get_ldap_user(self, username):
if username is None or username == '':
return None, None
Expand Down Expand Up @@ -138,14 +142,24 @@ def init_and_get_ldap_user(self, username):
server = Server(srv['host'], srv['port'], srv['use_ssl'], get_info=srv['get_info'])
else:
server = Server(srv['host'], srv['port'], srv['use_ssl'])

# TLS Settings:
if 'tls' in srv:
server.tls = srv['tls']
self.tls_bool = True
LDAP3ADBackend.pool.add(server)

# Check to see if tls is enabled in the instance, alter the bind method it True
if self.tls_bool is True:
bind = AUTO_BIND_TLS_BEFORE_BIND
else:
bind = AUTO_BIND_NO_TLS

# then, try to connect with user/pass from settings
con = Connection(LDAP3ADBackend.pool, auto_bind=True, client_strategy=SYNC, user=settings.LDAP_BIND_USER,
con = Connection(LDAP3ADBackend.pool, auto_bind=bind, client_strategy=SYNC, user=settings.LDAP_BIND_USER,
password=getattr(settings, password_field) or settings.LDAP_BIND_PASSWORD,
authentication=authentication, check_names=True)


# search for the desired user
user_dn = None
user_attribs = None
Expand Down Expand Up @@ -185,7 +199,14 @@ def authenticate(self, request, username=None, password=None):
if user_dn is not None and user_attribs is not None:
# now, we know the dn of the user, we try a simple bind. This way,
# the LDAP checks the password with it's algorithm and the active state of the user in one test
con = Connection(LDAP3ADBackend.pool, user=user_dn, password=password)

#Check for tls option here and tunnel connection.
if self.tls_bool is True:
bind = AUTO_BIND_TLS_BEFORE_BIND
else:
bind = AUTO_BIND_NO_TLS

con = Connection(LDAP3ADBackend.pool, user=user_dn, password=password, auto_bind=bind)
if con.bind():
logger.info("AUDIT SUCCESS LOGIN FOR: %s" % (username,))
user_model = get_user_model()
Expand All @@ -198,7 +219,7 @@ def authenticate(self, request, username=None, password=None):
user_model.bu = lambda: None
try:
# try to retrieve user from database and update it
username_field = getattr(settings, 'LDAP_USER_MODEL_USERNAME_FIELD', 'username')
username_field = getattr(settings, 'LDAP_USER_MODEL_USERNAME_FIELD', 'username')
lookup_username = user_attribs[settings.LDAP_ATTRIBUTES_MAP[username_field]]
usr = user_model.objects.get(**{"{0}__iexact".format(username_field): lookup_username})
except user_model.DoesNotExist:
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

setup(
name='django-auth-ldap3-ad',
version='1.6.33',
version='1.6.40',
packages=['django_auth_ldap3_ad'],
url='https://github.com/Lucterios2/django_auth_ldap3_ad',
license='GPL V3',
Expand Down