[Python-modules-commits] [django-auth-ldap] 01/08: Import django-auth-ldap_1.2.13+dfsg.orig.tar.gz
Michael Fladischer
fladi at moszumanska.debian.org
Thu Jul 6 20:41:27 UTC 2017
This is an automated email from the git hooks/post-receive script.
fladi pushed a commit to branch master
in repository django-auth-ldap.
commit 058058d4997149c3ae278a2ff7812814d62c02d2
Author: Michael Fladischer <FladischerMichael at fladi.at>
Date: Thu Jul 6 21:00:38 2017 +0200
Import django-auth-ldap_1.2.13+dfsg.orig.tar.gz
---
CHANGES | 11 +++
PKG-INFO | 4 +-
django_auth_ldap.egg-info/PKG-INFO | 4 +-
django_auth_ldap.egg-info/SOURCES.txt | 1 +
django_auth_ldap.egg-info/requires.txt | 2 +-
django_auth_ldap/__init__.py | 2 +-
django_auth_ldap/backend.py | 84 +++++++++++++++++--
django_auth_ldap/config.py | 4 +
django_auth_ldap/tests.py | 149 +++++++++++++++++++++++++++++++--
docs/source/.conf.py.swp | Bin 0 -> 16384 bytes
docs/source/conf.py | 2 +-
docs/source/permissions.rst | 39 +++++----
docs/source/reference.rst | 26 +++++-
setup.py | 4 +-
test/settings.py | 5 ++
tox.ini | 6 +-
16 files changed, 292 insertions(+), 51 deletions(-)
diff --git a/CHANGES b/CHANGES
index db447f4..bcbb03c 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,14 @@
+v1.2.13 - 2017-06-19 - Selective group mirroring
+------------------------------------------------
+
+- Support selective group mirroring with :setting:`AUTH_LDAP_MIRROR_GROUPS` and
+ :setting:`AUTH_LDAP_MIRROR_GROUPS_EXCEPT`.
+
+- Fix `#73`_: Work around Django 1.11 bug with multiple authentication backends.
+
+.. _#73: https://bitbucket.org/psagers/django-auth-ldap/issues/73/
+
+
v1.2.12 - 2017-05-20 - Complex group queries
--------------------------------------------
diff --git a/PKG-INFO b/PKG-INFO
index 8f0b616..30b644a 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: django-auth-ldap
-Version: 1.2.12
+Version: 1.2.13
Summary: Django LDAP authentication backend
Home-page: http://bitbucket.org/psagers/django-auth-ldap/
Author: Peter Sagerson
@@ -78,7 +78,6 @@ Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Web Environment
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2
-Classifier: Programming Language :: Python :: 2.6
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.3
@@ -86,7 +85,6 @@ Classifier: Programming Language :: Python :: 3.4
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Framework :: Django
-Classifier: Framework :: Django :: 1.4
Classifier: Framework :: Django :: 1.5
Classifier: Framework :: Django :: 1.6
Classifier: Framework :: Django :: 1.7
diff --git a/django_auth_ldap.egg-info/PKG-INFO b/django_auth_ldap.egg-info/PKG-INFO
index 8f0b616..30b644a 100644
--- a/django_auth_ldap.egg-info/PKG-INFO
+++ b/django_auth_ldap.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: django-auth-ldap
-Version: 1.2.12
+Version: 1.2.13
Summary: Django LDAP authentication backend
Home-page: http://bitbucket.org/psagers/django-auth-ldap/
Author: Peter Sagerson
@@ -78,7 +78,6 @@ Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Web Environment
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2
-Classifier: Programming Language :: Python :: 2.6
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.3
@@ -86,7 +85,6 @@ Classifier: Programming Language :: Python :: 3.4
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Framework :: Django
-Classifier: Framework :: Django :: 1.4
Classifier: Framework :: Django :: 1.5
Classifier: Framework :: Django :: 1.6
Classifier: Framework :: Django :: 1.7
diff --git a/django_auth_ldap.egg-info/SOURCES.txt b/django_auth_ldap.egg-info/SOURCES.txt
index a3bec28..3c08f18 100644
--- a/django_auth_ldap.egg-info/SOURCES.txt
+++ b/django_auth_ldap.egg-info/SOURCES.txt
@@ -46,6 +46,7 @@ docs/archive/versions/1.0.19/_static/up-pressed.png
docs/archive/versions/1.0.19/_static/up.png
docs/archive/versions/1.0.19/_static/websupport.js
docs/ext/daldocs.py
+docs/source/.conf.py.swp
docs/source/.spell.utf-8.add
docs/source/.spell.utf-8.add.spl
docs/source/authentication.rst
diff --git a/django_auth_ldap.egg-info/requires.txt b/django_auth_ldap.egg-info/requires.txt
index 6d5787b..8f1fe2c 100644
--- a/django_auth_ldap.egg-info/requires.txt
+++ b/django_auth_ldap.egg-info/requires.txt
@@ -1,2 +1,2 @@
django
-python-ldap >= 2.0
+pyldap
diff --git a/django_auth_ldap/__init__.py b/django_auth_ldap/__init__.py
index 4bdfabd..b426daa 100644
--- a/django_auth_ldap/__init__.py
+++ b/django_auth_ldap/__init__.py
@@ -1,2 +1,2 @@
-version = (1, 2, 12)
+version = (1, 2, 13)
version_string = '.'.join(map(str, version))
diff --git a/django_auth_ldap/backend.py b/django_auth_ldap/backend.py
index 4c6d698..70f2e76 100644
--- a/django_auth_ldap/backend.py
+++ b/django_auth_ldap/backend.py
@@ -52,6 +52,7 @@ import operator
import pprint
import sys
import traceback
+import warnings
from django.contrib.auth.models import User, Group, Permission
import django.conf
@@ -88,7 +89,7 @@ try:
except NameError:
basestring = str
-from django_auth_ldap.config import _LDAPConfig, LDAPGroupQuery, LDAPSearch
+from django_auth_ldap.config import ConfigurationWarning, _LDAPConfig, LDAPGroupQuery, LDAPSearch
logger = _LDAPConfig.get_logger()
@@ -165,7 +166,7 @@ class LDAPBackend(object):
# The Django auth backend API
#
- def authenticate(self, username, password, **kwargs):
+ def authenticate(self, request=None, username=None, password=None, **kwargs):
if bool(password) or self.settings.PERMIT_EMPTY_PASSWORD:
ldap_user = _LDAPUser(self, username=username.strip())
user = ldap_user.authenticate(password)
@@ -570,7 +571,8 @@ class _LDAPUser(object):
self._populate_user()
save_user = True
- if self.settings.MIRROR_GROUPS:
+ if bool(self.settings.MIRROR_GROUPS) or bool(self.settings.MIRROR_GROUPS_EXCEPT):
+ self._normalize_mirror_settings()
self._mirror_groups()
# Give the client a chance to finish populating the user just before
@@ -696,6 +698,55 @@ class _LDAPUser(object):
return query
+ def _normalize_mirror_settings(self):
+ """
+ Validates the group mirroring settings and converts them as necessary.
+ """
+ def malformed_mirror_groups_except():
+ return ImproperlyConfigured(
+ "{} must be a collection of group names".format(
+ self.settings._name('MIRROR_GROUPS_EXCEPT')
+ )
+ )
+
+ def malformed_mirror_groups():
+ return ImproperlyConfigured(
+ "{} must be True or a collection of group names".format(
+ self.settings._name('MIRROR_GROUPS')
+ )
+ )
+
+ mge = self.settings.MIRROR_GROUPS_EXCEPT
+ mg = self.settings.MIRROR_GROUPS
+
+ if mge is not None:
+ if isinstance(mge, (set, frozenset)):
+ pass
+ elif isinstance(mge, (list, tuple)):
+ mge = self.settings.MIRROR_GROUPS_EXCEPT = frozenset(mge)
+ else:
+ raise malformed_mirror_groups_except()
+
+ if not all(isinstance(value, basestring) for value in mge):
+ raise malformed_mirror_groups_except()
+ elif bool(mg):
+ warnings.warn(ConfigurationWarning("Ignoring {} in favor of {}".format(
+ self.settings._name("MIRROR_GROUPS"),
+ self.settings._name("MIRROR_GROUPS_EXCEPT")
+ )))
+ mg = self.settings.MIRROR_GROUPS = None
+
+ if mg is not None:
+ if isinstance(mg, (bool, set, frozenset)):
+ pass
+ elif isinstance(mg, (list, tuple)):
+ mg = self.settings.MIRROR_GROUPS = frozenset(mg)
+ else:
+ raise malformed_mirror_groups()
+
+ if isinstance(mg, (set, frozenset)) and (not all(isinstance(value, basestring) for value in mg)):
+ raise malformed_mirror_groups()
+
def _mirror_groups(self):
"""
Mirrors the user's LDAP groups in the Django database and updates the
@@ -704,6 +755,24 @@ class _LDAPUser(object):
target_group_names = frozenset(self._get_groups().get_group_names())
current_group_names = frozenset(self._user.groups.values_list('name', flat=True).iterator())
+ # These were normalized to sets above.
+ MIRROR_GROUPS_EXCEPT = self.settings.MIRROR_GROUPS_EXCEPT
+ MIRROR_GROUPS = self.settings.MIRROR_GROUPS
+
+ # If the settings are white- or black-listing groups, we'll update
+ # target_group_names such that we won't modify the membership of groups
+ # beyond our purview.
+ if isinstance(MIRROR_GROUPS_EXCEPT, (set, frozenset)):
+ target_group_names = (
+ (target_group_names - MIRROR_GROUPS_EXCEPT) |
+ (current_group_names & MIRROR_GROUPS_EXCEPT)
+ )
+ elif isinstance(MIRROR_GROUPS, (set, frozenset)):
+ target_group_names = (
+ (target_group_names & MIRROR_GROUPS) |
+ (current_group_names - MIRROR_GROUPS)
+ )
+
if target_group_names != current_group_names:
existing_groups = list(Group.objects.filter(name__in=target_group_names).iterator())
existing_group_names = frozenset(group.name for group in existing_groups)
@@ -804,8 +873,10 @@ class _LDAPUserGroups(object):
def _init_group_settings(self):
"""
- Loads the settings we need to deal with groups. Raises
- ImproperlyConfigured if anything's not right.
+ Loads the settings we need to deal with groups.
+
+ Raises ImproperlyConfigured if anything's not right.
+
"""
self._group_type = self.settings.GROUP_TYPE
if self._group_type is None:
@@ -920,7 +991,8 @@ class LDAPSettings(object):
'GROUP_CACHE_TIMEOUT': None,
'GROUP_SEARCH': None,
'GROUP_TYPE': None,
- 'MIRROR_GROUPS': False,
+ 'MIRROR_GROUPS': None,
+ 'MIRROR_GROUPS_EXCEPT': None,
'PERMIT_EMPTY_PASSWORD': False,
'PROFILE_ATTR_MAP': {},
'PROFILE_FLAGS_BY_GROUP': {},
diff --git a/django_auth_ldap/config.py b/django_auth_ldap/config.py
index 58c612e..b38e5fa 100644
--- a/django_auth_ldap/config.py
+++ b/django_auth_ldap/config.py
@@ -41,6 +41,10 @@ except ImportError: # Django < 1.5
from django.utils.encoding import smart_str as force_str
+class ConfigurationWarning(UserWarning):
+ pass
+
+
class _LDAPConfig(object):
"""
A private class that loads and caches some global objects.
diff --git a/django_auth_ldap/tests.py b/django_auth_ldap/tests.py
index 8661808..6b877b5 100644
--- a/django_auth_ldap/tests.py
+++ b/django_auth_ldap/tests.py
@@ -84,6 +84,7 @@ class LDAPTest(TestCase):
people = ("ou=people,o=test", {"ou": "people"})
groups = ("ou=groups,o=test", {"ou": "groups"})
moregroups = ("ou=moregroups,o=test", {"ou": "moregroups"})
+ mirror_groups = ("ou=mirror_groups,o=test", {"ou": "mirror_groups"})
alice = ("uid=alice,ou=people,o=test", {
"uid": ["alice"],
@@ -166,7 +167,7 @@ class LDAPTest(TestCase):
"member": ["uid=bob,ou=people,o=test"]
})
- # grouOfNames objects for LDAPGroupQuery testing
+ # groupOfNames objects for LDAPGroupQuery testing
alice_gon = ("cn=alice_gon,ou=query_groups,o=test", {
"cn": ["alice_gon"],
"objectClass": ["groupOfNames"],
@@ -183,6 +184,28 @@ class LDAPTest(TestCase):
"member": ["uid=bob,ou=people,o=test"]
})
+ # groupOfNames objects for selective group mirroring.
+ mirror1 = ("cn=mirror1,ou=mirror_groups,o=test", {
+ "cn": ["mirror1"],
+ "objectClass": ["groupOfNames"],
+ "member": ["uid=alice,ou=people,o=test"]
+ })
+ mirror2 = ("cn=mirror2,ou=mirror_groups,o=test", {
+ "cn": ["mirror2"],
+ "objectClass": ["groupOfNames"],
+ "member": []
+ })
+ mirror3 = ("cn=mirror3,ou=mirror_groups,o=test", {
+ "cn": ["mirror3"],
+ "objectClass": ["groupOfNames"],
+ "member": ["uid=alice,ou=people,o=test"]
+ })
+ mirror4 = ("cn=mirror4,ou=mirror_groups,o=test", {
+ "cn": ["mirror4"],
+ "objectClass": ["groupOfNames"],
+ "member": []
+ })
+
# nisGroup objects
active_nis = ("cn=active_nis,ou=groups,o=test", {
"cn": ["active_nis"],
@@ -220,12 +243,13 @@ class LDAPTest(TestCase):
"member": ["cn=parent_gon,ou=groups,o=test"]
})
- directory = dict([top, people, groups, moregroups, alice, bob, dressler,
- nobody, active_px, staff_px, superuser_px, empty_gon,
- active_gon, staff_gon, superuser_gon, other_gon,
- alice_gon, mutual_gon, bob_gon,
- active_nis, staff_nis, superuser_nis,
- parent_gon, nested_gon, circular_gon])
+ directory = dict([
+ top, people, groups, moregroups, mirror_groups, alice, bob, dressler,
+ nobody, active_px, staff_px, superuser_px, empty_gon, active_gon,
+ staff_gon, superuser_gon, other_gon, alice_gon, mutual_gon, bob_gon,
+ mirror1, mirror2, mirror3, mirror4, active_nis, staff_nis,
+ superuser_nis, parent_gon, nested_gon, circular_gon
+ ])
@classmethod
def configure_logger(cls):
@@ -326,6 +350,16 @@ class LDAPTest(TestCase):
['initialize', 'simple_bind_s']
)
+ @override_settings(AUTH_LDAP_USER_SEARCH=LDAPSearch("ou=people,o=test", ldap.SCOPE_SUBTREE, '(uid=%(user)s)'))
+ def test_login_with_multiple_auth_backends(self):
+ auth = self.client.login(username='alice', password='password')
+ self.assertTrue(auth)
+
+ @override_settings(AUTH_LDAP_USER_SEARCH=LDAPSearch("ou=people,o=test", ldap.SCOPE_SUBTREE, '(uid=%(user)s)'))
+ def test_bad_login_with_multiple_auth_backends(self):
+ auth = self.client.login(username='invalid', password='i_do_not_exist')
+ self.assertFalse(auth)
+
def test_simple_bind_escaped(self):
""" Bind with a username that requires escaping. """
self._init_settings(
@@ -639,7 +673,7 @@ class LDAPTest(TestCase):
['initialize', 'simple_bind_s', 'simple_bind_s', 'search_s']
)
- def test_poplate_with_attrlist(self):
+ def test_populate_with_attrlist(self):
self._init_settings(
USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
USER_ATTR_MAP={'first_name': 'givenName', 'last_name': 'sn'},
@@ -1249,6 +1283,105 @@ class LDAPTest(TestCase):
)
self.assertEqual(set(alice.groups.all()), set(Group.objects.all()))
+ #
+ # When selectively mirroring groups, there are eight scenarios for any
+ # given user/group pair:
+ #
+ # (is-member-in-LDAP, not-member-in-LDAP)
+ # x (is-member-in-Django, not-member-in-Django)
+ # x (synced, not-synced)
+ #
+ # The four test cases below take these scenarios four at a time for each of
+ # the two settings.
+
+ def test_group_mirroring_whitelist_update(self):
+ self._init_settings(
+ USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
+ GROUP_SEARCH=LDAPSearch('ou=mirror_groups,o=test', ldap.SCOPE_SUBTREE,
+ '(objectClass=groupOfNames)'),
+ GROUP_TYPE=GroupOfNamesType(),
+ MIRROR_GROUPS=['mirror1', 'mirror2']
+ )
+
+ groups = {}
+ for name in ('mirror{}'.format(i) for i in range(1, 5)):
+ groups[name] = Group.objects.create(name=name)
+ alice = self.backend.populate_user('alice')
+ alice.groups = [groups['mirror2'], groups['mirror4']]
+
+ alice = self.backend.authenticate(username='alice', password='password')
+
+ self.assertEqual(
+ set(alice.groups.values_list("name", flat=True)),
+ {'mirror1', 'mirror4'}
+ )
+
+ def test_group_mirroring_whitelist_noop(self):
+ self._init_settings(
+ USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
+ GROUP_SEARCH=LDAPSearch('ou=mirror_groups,o=test', ldap.SCOPE_SUBTREE,
+ '(objectClass=groupOfNames)'),
+ GROUP_TYPE=GroupOfNamesType(),
+ MIRROR_GROUPS=['mirror1', 'mirror2']
+ )
+
+ groups = {}
+ for name in ('mirror{}'.format(i) for i in range(1, 5)):
+ groups[name] = Group.objects.create(name=name)
+ alice = self.backend.populate_user('alice')
+ alice.groups = [groups['mirror1'], groups['mirror3']]
+
+ alice = self.backend.authenticate(username='alice', password='password')
+
+ self.assertEqual(
+ set(alice.groups.values_list("name", flat=True)),
+ {'mirror1', 'mirror3'}
+ )
+
+ def test_group_mirroring_blacklist_update(self):
+ self._init_settings(
+ USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
+ GROUP_SEARCH=LDAPSearch('ou=mirror_groups,o=test', ldap.SCOPE_SUBTREE,
+ '(objectClass=groupOfNames)'),
+ GROUP_TYPE=GroupOfNamesType(),
+ MIRROR_GROUPS_EXCEPT=['mirror1', 'mirror2']
+ )
+
+ groups = {}
+ for name in ('mirror{}'.format(i) for i in range(1, 5)):
+ groups[name] = Group.objects.create(name=name)
+ alice = self.backend.populate_user('alice')
+ alice.groups = [groups['mirror2'], groups['mirror4']]
+
+ alice = self.backend.authenticate(username='alice', password='password')
+
+ self.assertEqual(
+ set(alice.groups.values_list("name", flat=True)),
+ {'mirror2', 'mirror3'}
+ )
+
+ def test_group_mirroring_blacklist_noop(self):
+ self._init_settings(
+ USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
+ GROUP_SEARCH=LDAPSearch('ou=mirror_groups,o=test', ldap.SCOPE_SUBTREE,
+ '(objectClass=groupOfNames)'),
+ GROUP_TYPE=GroupOfNamesType(),
+ MIRROR_GROUPS_EXCEPT=['mirror1', 'mirror2']
+ )
+
+ groups = {}
+ for name in ('mirror{}'.format(i) for i in range(1, 5)):
+ groups[name] = Group.objects.create(name=name)
+ alice = self.backend.populate_user('alice')
+ alice.groups = [groups['mirror1'], groups['mirror3']]
+
+ alice = self.backend.authenticate(username='alice', password='password')
+
+ self.assertEqual(
+ set(alice.groups.values_list("name", flat=True)),
+ {'mirror1', 'mirror3'}
+ )
+
def test_authorize_external_users(self):
self._init_settings(
USER_DN_TEMPLATE='uid=%(user)s,ou=people,o=test',
diff --git a/docs/source/.conf.py.swp b/docs/source/.conf.py.swp
new file mode 100644
index 0000000..6b50423
Binary files /dev/null and b/docs/source/.conf.py.swp differ
diff --git a/docs/source/conf.py b/docs/source/conf.py
index e0ac649..fd0d8bc 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -59,7 +59,7 @@ copyright = u'2009, Peter Sagerson'
# The short X.Y version.
version = '1.1'
# The full version, including alpha/beta/rc tags.
-release = '1.2.12'
+release = '1.2.13'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
diff --git a/docs/source/permissions.rst b/docs/source/permissions.rst
index 9a15103..1146c6d 100644
--- a/docs/source/permissions.rst
+++ b/docs/source/permissions.rst
@@ -43,22 +43,29 @@ Group Mirroring
---------------
The second way to turn LDAP group memberships into permissions is to mirror the
-groups themselves. If :setting:`AUTH_LDAP_MIRROR_GROUPS` is ``True``, then every
-time a user logs in, :class:`~django_auth_ldap.backend.LDAPBackend` will update
-the database with the user's LDAP groups. Any group that doesn't exist will be
-created and the user's Django group membership will be updated to exactly match
-his LDAP group membership. Note that if the LDAP server has nested groups, the
-Django database will end up with a flattened representation. For group mirroring
-to have any effect, you of course need
-:class:`~django.contrib.auth.backends.ModelBackend` installed as an
-authentication backend.
-
-The main difference between this approach and
-:setting:`AUTH_LDAP_FIND_GROUP_PERMS` is that
-:setting:`AUTH_LDAP_FIND_GROUP_PERMS` will query for LDAP group membership
-either for every request or according to the cache timeout. With group
-mirroring, membership will be updated when the user authenticates. This may not
-be appropriate for sites with long session timeouts.
+groups themselves. This approach has some important disadvantages and should be
+avoided if possible. For one thing, membership will only be updated when the
+user authenticates, which may be especially inappropriate for sites with long
+session timeouts.
+
+If :setting:`AUTH_LDAP_MIRROR_GROUPS` is ``True``, then every time a user logs
+in, :class:`~django_auth_ldap.backend.LDAPBackend` will update the database with
+the user's LDAP groups. Any group that doesn't exist will be created and the
+user's Django group membership will be updated to exactly match their LDAP group
+membership. If the LDAP server has nested groups, the Django database will end
+up with a flattened representation. For group mirroring to have any effect, you
+of course need :class:`~django.contrib.auth.backends.ModelBackend` installed as
+an authentication backend.
+
+By default, we assume that LDAP is the sole authority on group membership; if
+you remove a user from a group in LDAP, they will be removed from the
+corresponding Django group the next time they log in. It is also possible to
+have django-auth-ldap ignore some Django groups, presumably because they are
+managed manually or through some other mechanism. If
+:setting:`AUTH_LDAP_MIRROR_GROUPS` is a list of group names, we will manage
+these groups and no others. If :setting:`AUTH_LDAP_MIRROR_GROUPS_EXCEPT` is a
+list of group names, we will manage all groups except those named;
+:setting:`AUTH_LDAP_MIRROR_GROUPS` is ignored in this case.
Non-LDAP Users
diff --git a/docs/source/reference.rst b/docs/source/reference.rst
index 834f120..84c64de 100644
--- a/docs/source/reference.rst
+++ b/docs/source/reference.rst
@@ -176,13 +176,31 @@ of group returned by :setting:`AUTH_LDAP_GROUP_SEARCH`.
AUTH_LDAP_MIRROR_GROUPS
~~~~~~~~~~~~~~~~~~~~~~~
-Default: ``False``
+Default: ``None``
If ``True``, :class:`~django_auth_ldap.backend.LDAPBackend` will mirror a user's
LDAP group membership in the Django database. Any time a user authenticates, we
-will create all of his LDAP groups as Django groups and update his Django group
-membership to exactly match his LDAP group membership. If the LDAP server has
-nested groups, the Django database will end up with a flattened representation.
+will create all of their LDAP groups as Django groups and update their Django
+group membership to exactly match their LDAP group membership. If the LDAP
+server has nested groups, the Django database will end up with a flattened
+representation.
+
+This can also be a list or other collection of group names, in which case we'll
+only mirror those groups and leave the rest alone. This is ignored if
+:setting:`AUTH_LDAP_MIRROR_GROUPS_EXCEPT` is set.
+
+
+.. setting:: AUTH_LDAP_MIRROR_GROUPS_EXCEPT
+
+AUTH_LDAP_MIRROR_GROUPS_EXCEPT
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Default: ``None``
+
+If this is not ``None``, it must be a list or other collection of group names.
+This will enable group mirroring, except that we'll never change the membership
+of the indicated groups. :setting:`AUTH_LDAP_MIRROR_GROUPS` is ignored in this
+case.
.. setting:: AUTH_LDAP_PERMIT_EMPTY_PASSWORD
diff --git a/setup.py b/setup.py
index c32174e..6397eff 100644
--- a/setup.py
+++ b/setup.py
@@ -10,7 +10,7 @@ PY3 = (sys.version_info[0] == 3)
setup(
name="django-auth-ldap",
- version="1.2.12",
+ version="1.2.13",
description="Django LDAP authentication backend",
long_description=open('README').read(),
url="http://bitbucket.org/psagers/django-auth-ldap/",
@@ -23,7 +23,6 @@ setup(
"Environment :: Web Environment",
"Programming Language :: Python",
"Programming Language :: Python :: 2",
- "Programming Language :: Python :: 2.6",
"Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.3",
@@ -31,7 +30,6 @@ setup(
"Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6",
"Framework :: Django",
- "Framework :: Django :: 1.4",
"Framework :: Django :: 1.5",
"Framework :: Django :: 1.6",
"Framework :: Django :: 1.7",
diff --git a/test/settings.py b/test/settings.py
index 43b5801..0c1dd84 100644
--- a/test/settings.py
+++ b/test/settings.py
@@ -31,3 +31,8 @@ INSTALLED_APPS = (
MIDDLEWARE_CLASSES = []
AUTH_USER_MODEL = 'auth.User'
+
+AUTHENTICATION_BACKENDS = [
+ 'django_auth_ldap.backend.LDAPBackend',
+ 'django.contrib.auth.backends.ModelBackend',
+]
diff --git a/tox.ini b/tox.ini
index 5c97066..8a6e543 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,4 +1,4 @@
-[pep8]
+[pycodestyle]
max-line-length = 120
[flake8]
@@ -7,7 +7,6 @@ max-line-length = 120
[tox]
envlist = py36-static,
- py26-django{13,14,15},
py27-django15
py{27,33}-django{15,16},
py{27,33,34}-django17
@@ -19,8 +18,6 @@ envlist = py36-static,
changedir = test
commands = {envpython} manage.py test django_auth_ldap
deps = mockldap>=0.2.7
- django13: Django>=1.3,<1.4
- django14: Django>=1.4,<1.5
django15: Django>=1.5,<1.6
django16: Django>=1.6,<1.7
django17: Django>=1.7,<1.8
@@ -30,7 +27,6 @@ deps = mockldap>=0.2.7
django111: Django>=1.11,<2.0
basepython =
- py26: python2.6
py27: python2.7
py33: python3.3
py34: python3.4
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/django-auth-ldap.git
More information about the Python-modules-commits
mailing list