[Python-modules-commits] [django-python3-ldap] 01/05: Import django-python3-ldap_0.10.0.orig.tar.gz

Michael Fladischer fladi at moszumanska.debian.org
Tue Jun 20 08:04:34 UTC 2017


This is an automated email from the git hooks/post-receive script.

fladi pushed a commit to branch master
in repository django-python3-ldap.

commit 8f93434f8126879b4d432f7094aee180c4b18b87
Author: Michael Fladischer <FladischerMichael at fladi.at>
Date:   Tue Jun 20 09:59:03 2017 +0200

    Import django-python3-ldap_0.10.0.orig.tar.gz
---
 CHANGELOG.rst                                      | 109 +++++++++++++++++++++
 MANIFEST.in                                        |   2 +
 PKG-INFO                                           |   2 +-
 README.rst                                         |  22 +++--
 django_python3_ldap.egg-info/PKG-INFO              |   2 +-
 django_python3_ldap.egg-info/SOURCES.txt           |   6 +-
 django_python3_ldap.egg-info/requires.txt          |   2 +-
 django_python3_ldap/__init__.py                    |   2 +-
 django_python3_ldap/ldap.py                        |  59 +++++++++--
 .../management/commands/ldap_sync_users.py         |   4 +-
 django_python3_ldap/tests.py                       |  25 +++++
 django_python3_ldap/utils.py                       |  17 +++-
 setup.py                                           |   2 +-
 tests/django_python3_ldap_test/__init__.py         |   0
 tests/django_python3_ldap_test/settings.py         |  98 ++++++++++++++++++
 tests/manage.py                                    |  10 ++
 16 files changed, 336 insertions(+), 26 deletions(-)

diff --git a/CHANGELOG.rst b/CHANGELOG.rst
new file mode 100644
index 0000000..bb9fca5
--- /dev/null
+++ b/CHANGELOG.rst
@@ -0,0 +1,109 @@
+django-python3-ldap changelog
+=============================
+
+0.10.0
+------
+
+- If `settings.LDAP_AUTH_CONNECTION_USERNAME` or `settings.LDAP_AUTH_CONNECTION_PASSWORD` is set, then it will be used to query the LDAP database for user details during authentication.
+- Added `django_python3_ldap.utils.format_username_active_directory_principal` option for formatting user-principal-name (e.g. "user at domain.com") Active Directory usernames.
+
+
+0.9.14
+------
+
+- Django 1.11 compatibility (@aritas1).
+
+
+0.9.13
+------
+
+- Fixed issue with LDAP servers returning attributes that are not a list (@etianen).
+
+
+0.9.12
+------
+
+- Update for compatibility with ldap3 2.x release (@etianen).
+
+
+0.9.11
+------
+
+- Added support for LDAP referrals (@etianen).
+- Fixed issue with missing LDAP attributes (@smills2929).
+- Tweaks and bugfixes (@smills2929).
+
+
+0.9.10
+------
+
+- Django 1.10 compatibility (@etianen, @frennkie).
+- Added operational LDAP attributes to ``iter_users`` (@frennkie).
+- Dropped Django 1.7 compatibility (@etianen).
+- Dropped Python 3.2 and 3.3 compatibility (@etianen).
+
+
+0.9.9
+-----
+
+- Fixing anonymous bind in some LDAP servers (@etianen).
+
+
+0.9.8
+-----
+
+- Fixing security vulnerability allowing users to authenticate with a valid username but with an empty password if anonymous authentication is allowed on the LDAP server (Petros Moisiadis).
+- Fixing sync_users command for Microsoft Active Directory (@jjagielka).
+
+
+0.9.7
+-----
+
+- Ability to configure extra filters for user lookup using LDAP_AUTH_SEARCH_FILTERS (@etianen, @Ernest0x).
+- Support for Active Directory LDAP servers (@etianen, @brandonusher).
+- Python 2.7 compatibility (@NotSqrt).
+- Ability to configure relations on loaded user models using LDAP_AUTH_SYNC_USER_RELATIONS (@mnach).
+- Switched to specifying paths to functions using dotted string paths in settings (@mnach).
+
+
+0.9.6
+-----
+
+- Added settings option for a username and password to be specified incase anonymous user queries are not allowed (@brandonusher).
+
+
+0.9.5
+-----
+
+- Fixing security vulnerability where username and password could be transmitted in plain text before starting TLS (reported by Weitzhofer Bernhard).
+
+
+0.9.4
+-----
+
+- Fixing broken ldap3 dependency (@levisaya).
+- Honoring LDAP_AUTH_CLEAN_USER_DATA setting (@etianen, @akaariai).
+
+
+0.9.3
+-----
+
+- Fixing broken python3-ldap dependency (@ricard33).
+
+
+0.9.2
+-----
+
+- Added setting for initiating TLS on connection (@saraheiting).
+
+
+0.9.1
+-----
+
+- Adding ldap_promote management command.
+
+
+0.9.0
+-----
+
+- First production release.
diff --git a/MANIFEST.in b/MANIFEST.in
index 9d5d250..0bbcd8b 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,2 +1,4 @@
 include LICENSE
 include README.rst
+include CHANGELOG.rst
+recursive-include tests *.py
diff --git a/PKG-INFO b/PKG-INFO
index 536240e..ccffb8f 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: django-python3-ldap
-Version: 0.9.12
+Version: 0.10.0
 Summary: Django LDAP user authentication backend for Python 3.
 Home-page: https://github.com/etianen/django-python3-ldap
 Author: Dave Hall
diff --git a/README.rst b/README.rst
index 3774d8c..cabac67 100644
--- a/README.rst
+++ b/README.rst
@@ -80,8 +80,9 @@ Available settings
     # Sets the login domain for Active Directory users.
     LDAP_AUTH_ACTIVE_DIRECTORY_DOMAIN = None
 
-    # The LDAP username and password of a user for authenticating the `ldap_sync_users`
-    # management command. Set to None if you allow anonymous queries.
+    # The LDAP username and password of a user for querying the LDAP database for user
+    # details. If None, then the authenticated user will be used for querying, and
+    # the `ldap_sync_users` command will perform an anonymous query.
     LDAP_AUTH_CONNECTION_USERNAME = None
     LDAP_AUTH_CONNECTION_PASSWORD = None
 
@@ -90,18 +91,27 @@ Microsoft Active Directory support
 ----------------------------------
 
 django-python3-ldap is configured by default to support login via OpenLDAP. To connect to
-a Microsoft Active Directory, add the following line to your settings file.
+a Microsoft Active Directory, you need to modify your settings file.
+
+For simple usernames (e.g. "username"):
+
+.. code:: python
+
+    LDAP_AUTH_FORMAT_USERNAME = "django_python3_ldap.utils.format_username_active_directory"
+
+For down-level login name formats (e.g. "DOMAIN\\username"):
 
 .. code:: python
 
     LDAP_AUTH_FORMAT_USERNAME = "django_python3_ldap.utils.format_username_active_directory"
+    LDAP_AUTH_ACTIVE_DIRECTORY_DOMAIN = "DOMAIN"
 
-If your Active Directory server requires a domain to be supplied with the username,
-then also specify:
+For user-principal-name formats (e.g. "user at domain.com"):
 
 .. code:: python
 
-    LDAP_AUTH_ACTIVE_DIRECTORY_DOMAIN = "your_domain"
+    LDAP_AUTH_FORMAT_USERNAME = "django_python3_ldap.utils.format_username_active_directory_principal"
+    LDAP_AUTH_ACTIVE_DIRECTORY_DOMAIN = "domain.com"
 
 
 Can't get authentication to work?
diff --git a/django_python3_ldap.egg-info/PKG-INFO b/django_python3_ldap.egg-info/PKG-INFO
index 536240e..ccffb8f 100644
--- a/django_python3_ldap.egg-info/PKG-INFO
+++ b/django_python3_ldap.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: django-python3-ldap
-Version: 0.9.12
+Version: 0.10.0
 Summary: Django LDAP user authentication backend for Python 3.
 Home-page: https://github.com/etianen/django-python3-ldap
 Author: Dave Hall
diff --git a/django_python3_ldap.egg-info/SOURCES.txt b/django_python3_ldap.egg-info/SOURCES.txt
index ea2ae84..a05d835 100644
--- a/django_python3_ldap.egg-info/SOURCES.txt
+++ b/django_python3_ldap.egg-info/SOURCES.txt
@@ -1,3 +1,4 @@
+CHANGELOG.rst
 LICENSE
 MANIFEST.in
 README.rst
@@ -16,4 +17,7 @@ django_python3_ldap.egg-info/top_level.txt
 django_python3_ldap/management/__init__.py
 django_python3_ldap/management/commands/__init__.py
 django_python3_ldap/management/commands/ldap_promote.py
-django_python3_ldap/management/commands/ldap_sync_users.py
\ No newline at end of file
+django_python3_ldap/management/commands/ldap_sync_users.py
+tests/manage.py
+tests/django_python3_ldap_test/__init__.py
+tests/django_python3_ldap_test/settings.py
\ No newline at end of file
diff --git a/django_python3_ldap.egg-info/requires.txt b/django_python3_ldap.egg-info/requires.txt
index 3187fd1..698f788 100644
--- a/django_python3_ldap.egg-info/requires.txt
+++ b/django_python3_ldap.egg-info/requires.txt
@@ -1,2 +1,2 @@
 django>=1.8
-ldap3==2.2.0
+ldap3==2.2.3
diff --git a/django_python3_ldap/__init__.py b/django_python3_ldap/__init__.py
index c6b0a53..73f0bcc 100644
--- a/django_python3_ldap/__init__.py
+++ b/django_python3_ldap/__init__.py
@@ -3,4 +3,4 @@ Django LDAP user authentication backend for Python 3.
 """
 
 
-__version__ = (0, 9, 12)
+__version__ = (0, 10, 0)
diff --git a/django_python3_ldap/ldap.py b/django_python3_ldap/ldap.py
index 151502e..1bdc0ed 100644
--- a/django_python3_ldap/ldap.py
+++ b/django_python3_ldap/ldap.py
@@ -38,15 +38,21 @@ class Connection(object):
 
         attributes = user_data.get("attributes")
         if attributes is None:
+            logger.warning("LDAP user attributes empty")
             return None
 
         User = get_user_model()
 
         # Create the user data.
         user_fields = {
-            field_name: attributes.get(attribute_name, ("",))[0]
+            field_name: (
+                attributes[attribute_name][0]
+                if isinstance(attributes[attribute_name], (list, tuple)) else
+                attributes[attribute_name]
+            )
             for field_name, attribute_name
             in settings.LDAP_AUTH_USER_FIELDS.items()
+            if attribute_name in attributes
         }
         user_fields = import_func(settings.LDAP_AUTH_CLEAN_USER_DATA)(user_fields)
         # Create the user lookup.
@@ -60,9 +66,14 @@ class Connection(object):
             defaults=user_fields,
             **user_lookup
         )
+        # If the user was created, set them an unusable password.
+        if created:
+            user.set_unusable_password()
+            user.save()
         # Update relations
         import_func(settings.LDAP_AUTH_SYNC_USER_RELATIONS)(user, attributes)
         # All done!
+        logger.info("LDAP user lookup succeeded")
         return user
 
     def iter_users(self):
@@ -102,6 +113,7 @@ class Connection(object):
             size_limit=1,
         ):
             return self._get_or_create_user(self._connection.response[0])
+        logger.warning("LDAP user lookup failed")
         return None
 
 
@@ -114,6 +126,7 @@ def connection(**kwargs):
     in settings.LDAP_AUTH_USER_LOOKUP_FIELDS, plus a `password` argument.
     """
     # Format the DN for the username.
+    format_username = import_func(settings.LDAP_AUTH_FORMAT_USERNAME)
     kwargs = {
         key: value
         for key, value
@@ -124,28 +137,54 @@ def connection(**kwargs):
     password = None
     if kwargs:
         password = kwargs.pop("password")
-        username = import_func(settings.LDAP_AUTH_FORMAT_USERNAME)(kwargs)
-    # Make the connection.
+        username = format_username(kwargs)
+    # Configure the connection.
     if settings.LDAP_AUTH_USE_TLS:
         auto_bind = ldap3.AUTO_BIND_TLS_BEFORE_BIND
     else:
         auto_bind = ldap3.AUTO_BIND_NO_TLS
+    # Connect.
     try:
-        with ldap3.Connection(ldap3.Server(
-            settings.LDAP_AUTH_URL,
-            allowed_referral_hosts=[("*", True)]),
+        c = ldap3.Connection(
+            ldap3.Server(
+                settings.LDAP_AUTH_URL,
+                allowed_referral_hosts=[("*", True)],
+            ),
             user=username,
             password=password,
             auto_bind=auto_bind,
             raise_exceptions=True,
-        ) as c:
-            yield Connection(c)
+        )
     except LDAPException as ex:
-        logger.info("LDAP connect failed: {ex}".format(ex=ex))
+        logger.warning("LDAP connect failed: {ex}".format(ex=ex))
         yield None
+        return
+    # If the settings specify an alternative username and password for querying, rebind as that.
+    if (
+        (settings.LDAP_AUTH_CONNECTION_USERNAME or settings.LDAP_AUTH_CONNECTION_PASSWORD) and
+        (
+            settings.LDAP_AUTH_CONNECTION_USERNAME != username or
+            settings.LDAP_AUTH_CONNECTION_PASSWORD != password
+        )
+    ):
+        try:
+            c.rebind(
+                user=format_username({"username": settings.LDAP_AUTH_CONNECTION_USERNAME}),
+                password=settings.LDAP_AUTH_CONNECTION_PASSWORD,
+            )
+        except LDAPException as ex:
+            logger.warning("LDAP rebind failed: {ex}".format(ex=ex))
+            yield None
+            return
+    # Return the connection.
+    logger.info("LDAP connect succeeded")
+    try:
+        yield Connection(c)
+    finally:
+        c.unbind()
 
 
-def authenticate(**kwargs):
+def authenticate(*args, **kwargs):
     """
     Authenticates with the LDAP server, and returns
     the corresponding Django user instance.
diff --git a/django_python3_ldap/management/commands/ldap_sync_users.py b/django_python3_ldap/management/commands/ldap_sync_users.py
index 8a6abb5..ad725df 100644
--- a/django_python3_ldap/management/commands/ldap_sync_users.py
+++ b/django_python3_ldap/management/commands/ldap_sync_users.py
@@ -1,4 +1,4 @@
-from django.core.management.base import BaseCommand
+from django.core.management.base import BaseCommand, CommandError
 from django.db import transaction
 
 from django_python3_ldap import ldap
@@ -16,6 +16,8 @@ class Command(BaseCommand):
             username=settings.LDAP_AUTH_CONNECTION_USERNAME,
             password=settings.LDAP_AUTH_CONNECTION_PASSWORD,
         ) as connection:
+            if connection is None:
+                raise CommandError("Could not connect to LDAP server")
             for user in connection.iter_users():
                 if verbosity >= 1:
                     self.stdout.write("Synced {user}".format(
diff --git a/django_python3_ldap/tests.py b/django_python3_ldap/tests.py
index 3551bdc..fb2eca3 100644
--- a/django_python3_ldap/tests.py
+++ b/django_python3_ldap/tests.py
@@ -103,6 +103,31 @@ class TestLdap(TestCase):
             self.assertIsInstance(user, User)
             self.assertEqual(user.username, settings.LDAP_AUTH_TEST_USER_USERNAME)
 
+    def testAuthenticateWithRebind(self):
+        with self.settings(
+            LDAP_AUTH_USE_TLS=True,
+            LDAP_AUTH_CONNECTION_USERNAME=settings.LDAP_AUTH_TEST_USER_USERNAME,
+            LDAP_AUTH_CONNECTION_PASSWORD=settings.LDAP_AUTH_TEST_USER_PASSWORD,
+        ):
+            user = authenticate(
+                username=settings.LDAP_AUTH_TEST_USER_USERNAME,
+                password=settings.LDAP_AUTH_TEST_USER_PASSWORD,
+            )
+            self.assertIsInstance(user, User)
+            self.assertEqual(user.username, settings.LDAP_AUTH_TEST_USER_USERNAME)
+
+    def testAuthenticateWithFailedRebind(self):
+        with self.settings(
+            LDAP_AUTH_USE_TLS=True,
+            LDAP_AUTH_CONNECTION_USERNAME="bad" + settings.LDAP_AUTH_TEST_USER_USERNAME,
+            LDAP_AUTH_CONNECTION_PASSWORD=settings.LDAP_AUTH_TEST_USER_PASSWORD,
+        ):
+            user = authenticate(
+                username=settings.LDAP_AUTH_TEST_USER_USERNAME,
+                password=settings.LDAP_AUTH_TEST_USER_PASSWORD,
+            )
+            self.assertIs(user, None)
+
     # User synchronisation.
 
     def testSyncUsersCreatesUsers(self):
diff --git a/django_python3_ldap/utils.py b/django_python3_ldap/utils.py
index 0fc6b1a..794453a 100644
--- a/django_python3_ldap/utils.py
+++ b/django_python3_ldap/utils.py
@@ -4,7 +4,6 @@ Some useful LDAP utilities.
 
 import re
 import binascii
-from django.contrib.auth.hashers import make_password
 from django.utils.encoding import force_text
 from django.utils.module_loading import import_string
 from django.utils import six
@@ -60,8 +59,6 @@ def clean_user_data(model_fields):
     Transforms the user data loaded from
     LDAP into a form suitable for creating a user.
     """
-    # Create an unusable password for the user.
-    model_fields["password"] = make_password(None)
     return model_fields
 
 
@@ -97,6 +94,20 @@ def format_username_active_directory(model_fields):
     return username
 
 
+def format_username_active_directory_principal(model_fields):
+    """
+    Formats a user identifier into a username suitable for
+    binding to an Active Directory server.
+    """
+    username = model_fields["username"]
+    if settings.LDAP_AUTH_ACTIVE_DIRECTORY_DOMAIN:
+        username = "{username}@{domain}".format(
+            username=username,
+            domain=settings.LDAP_AUTH_ACTIVE_DIRECTORY_DOMAIN,
+        )
+    return username
+
+
 def sync_user_relations(user, ldap_attributes):
     # do nothing by default
     pass
diff --git a/setup.py b/setup.py
index df02bcd..a9f69a4 100644
--- a/setup.py
+++ b/setup.py
@@ -17,7 +17,7 @@ setup(
     packages=find_packages(),
     install_requires=[
         "django>=1.8",
-        "ldap3==2.2.0",
+        "ldap3==2.2.3",
     ],
     classifiers=[
         "Development Status :: 4 - Beta",
diff --git a/tests/django_python3_ldap_test/__init__.py b/tests/django_python3_ldap_test/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/django_python3_ldap_test/settings.py b/tests/django_python3_ldap_test/settings.py
new file mode 100644
index 0000000..eb699a8
--- /dev/null
+++ b/tests/django_python3_ldap_test/settings.py
@@ -0,0 +1,98 @@
+"""
+Django settings for django_python3_ldap_test project.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/1.7/topics/settings/
+
+For the full list of settings and their values, see
+https://docs.djangoproject.com/en/1.7/ref/settings/
+"""
+
+# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
+import os
+BASE_DIR = os.path.dirname(os.path.dirname(__file__))
+
+
+# Quick-start development settings - unsuitable for production
+# See https://docs.djangoproject.com/en/1.7/howto/deployment/checklist/
+
+# SECURITY WARNING: keep the secret key used in production secret!
+SECRET_KEY = '^vxc5sw2w^%02!vrk(#)am3ly#b$ykb!eu$bx*pto at v)&q8 at 9#'
+
+# SECURITY WARNING: don't run with debug turned on in production!
+DEBUG = True
+
+TEMPLATE_DEBUG = True
+
+ALLOWED_HOSTS = []
+
+
+# LDAP auth settings.
+
+LDAP_AUTH_URL = os.environ.get("LDAP_AUTH_URL", "ldap://localhost:389")
+
+LDAP_AUTH_SEARCH_BASE = os.environ.get("LDAP_AUTH_SEARCH_BASE", "")
+
+AUTHENTICATION_BACKENDS = (
+    "django_python3_ldap.auth.LDAPBackend",
+)
+
+
+# LDAP auth test settings.
+
+LDAP_AUTH_TEST_USER_USERNAME = os.environ.get("LDAP_AUTH_TEST_USER_USERNAME", "")
+
+LDAP_AUTH_TEST_USER_PASSWORD = os.environ.get("LDAP_AUTH_TEST_USER_PASSWORD", "")
+
+
+# Application definition
+
+INSTALLED_APPS = (
+    'django.contrib.admin',
+    'django.contrib.auth',
+    'django.contrib.contenttypes',
+    'django.contrib.sessions',
+    'django.contrib.messages',
+    'django.contrib.staticfiles',
+    'django_python3_ldap',
+)
+
+MIDDLEWARE_CLASSES = (
+    'django.contrib.sessions.middleware.SessionMiddleware',
+    'django.middleware.common.CommonMiddleware',
+    'django.middleware.csrf.CsrfViewMiddleware',
+    'django.contrib.auth.middleware.AuthenticationMiddleware',
+    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
+    'django.contrib.messages.middleware.MessageMiddleware',
+    'django.middleware.clickjacking.XFrameOptionsMiddleware',
+)
+
+
+# Database
+# https://docs.djangoproject.com/en/1.7/ref/settings/#databases
+
+DATABASES = {
+    'default': {
+        'ENGINE': 'django.db.backends.sqlite3',
+        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
+    }
+}
+
+# Internationalization
+# https://docs.djangoproject.com/en/1.7/topics/i18n/
+
+LANGUAGE_CODE = 'en-us'
+
+TIME_ZONE = 'UTC'
+
+USE_I18N = True
+
+USE_L10N = True
+
+USE_TZ = True
+
+
+# Static files (CSS, JavaScript, Images)
+# https://docs.djangoproject.com/en/1.7/howto/static-files/
+
+STATIC_URL = '/static/'
diff --git a/tests/manage.py b/tests/manage.py
new file mode 100755
index 0000000..89833b0
--- /dev/null
+++ b/tests/manage.py
@@ -0,0 +1,10 @@
+#!/usr/bin/env python
+import os
+import sys
+
+if __name__ == "__main__":
+    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django_python3_ldap_test.settings")
+
+    from django.core.management import execute_from_command_line
+
+    execute_from_command_line(sys.argv)

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/django-python3-ldap.git



More information about the Python-modules-commits mailing list