A python/django Active Directory group management abstraction that uses ldap3 as a backend for cross-platform compatibility.
Project description
=============================
ldap-groups
=============================
A python/django Active Directory group management abstraction that uses ldap3 as a backend for cross-platform compatibility.
Badges
------
.. image:: https://img.shields.io/travis/kavdev/ldap-groups/master.svg?style=flat-square
:target: https://travis-ci.org/kavdev/ldap-groups
.. image:: https://img.shields.io/codecov/c/github/kavdev/ldap-groups/master.svg?style=flat-square
:target: http://codecov.io/github/kavdev/ldap-groups?branch=master
.. image:: https://img.shields.io/requires/github/kavdev/ldap-groups.svg?style=flat-square
:target: https://requires.io/github/kavdev/ldap-groups/requirements/?branch=master
.. image:: https://img.shields.io/codacy/f8b8c71b805e4585b8c34ba7c02fbd0c.svg?style=flat-square
:target: https://www.codacy.com/app/kavdev/ldap-groups/dashboard
.. image:: https://img.shields.io/pypi/v/ldap-groups.svg?style=flat-square
:target: https://pypi.python.org/pypi/ldap-groups
.. image:: https://img.shields.io/pypi/dw/ldap-groups.svg?style=flat-square
:target: https://pypi.python.org/pypi/ldap-groups
.. image:: https://img.shields.io/github/issues/kavdev/ldap-groups.svg?style=flat-square
:target: https://github.com/kavdev/ldap-groups/issues
.. image:: https://img.shields.io/github/license/kavdev/ldap-groups.svg?style=flat-square
:target: https://github.com/kavdev/ldap-groups/blob/master/LICENSE
Installation
-----
Install ldap-groups with pip:
.. code-block:: bash
pip install ldap-groups
Add ldap-groups to ``INSTALLED_APPS`` (if you're using Django)
.. code:: python
INSTALLED_APPS = (
...
'ldap_groups',
...
)
Django Settings
---------------
There are a few settings that must be configured before ldap-groups will run.
*Mandatory*
* ``LDAP_GROUPS_SERVER_URI`` - The ldap server's uri, e.g. 'ldap://example.com'
* ``LDAP_GROUPS_BASE_DN`` - The base search dn, e.g. 'DC=example,DC=com'
*Optional*
* ``LDAP_GROUPS_BIND_DN`` - The bind user's DN
* ``LDAP_GROUPS_BIND_PASSWORD`` - The bind user's password
NOTE: while a bind user is optional, many servers' security settings will deny anonymous access.
* ``LDAP_GROUPS_USER_LOOKUP_ATTRIBUTE`` - The attribute by which to search when looking up users (should be unique). Defaults to ``'sAMAccountName'``.
* ``LDAP_GROUPS_USER_SEARCH_BASE_DN`` - The base dn to use when looking up users. Defaults to ``LDAP_GROUPS_BASE_DN``.
* ``LDAP_GROUPS_GROUP_LOOKUP_ATTRIBUTE`` - The attribute by which to search when looking up groups (should be unique). Defaults to ``'name'``.
* ``LDAP_GROUPS_GROUP_SEARCH_BASE_DN`` - The base dn to use when looking up groups. Defaults to ``LDAP_GROUPS_BASE_DN``.
* ``LDAP_GROUPS_ATTRIBUTE_LIST`` - A list of attributes returned for each member while pulling group members. An empty list should return all attributes. Defaults to ``['displayName', 'sAMAccountName', 'distinguishedName']``.
Usage
-----
In its current state, ldap-groups can perform the following functions:
* Get a specific attribute of a group
* Get all attributes of a group in dictionary form
* Get all members of a group and their attributes (users)
* Add a member to a group (user)
* Remove a member from a group (user)
* Add a child to a group (nested group)
* Remove a child from a group (nested group)
* Get all descendants of a group (groups and organizational units)
* Get all children of a group (groups and organizational units)
* Traverse to a specific child of a group
* Traverse to a group's parent
* Traverse to a group's ancestor
An ADGroup instance only requires one argument to function: a group's distinguished name.
Once the ADGroup is instantiated, the rest is fairly simple:
.. code:: python
from ldap_groups import ADGroup
GROUP_DN = "ou=users,dc=example,dc=com"
ACCOUNT_NAME = "jdoe"
NAME_ATTRIBUTE = "name"
TYPE_ATTRIBUTE = "objectClass"
class ADGroupModifier(object):
def __init__(self):
self.ad_group_instance = ADGroup(GROUP_DN)
def add_member(self):
self.ad_group_instance.add_member(ACCOUNT_NAME)
def remove_member(self):
self.ad_group_instance.remove_member(ACCOUNT_NAME)
def get_group_member_info(self):
return self.ad_group_instance.get_member_info()
class ADGroupInfo(object):
def __init__(self):
self.ad_group_instance = ADGroup(GROUP_DN)
def get_attributes(self):
return self.ad_group_instance.get_attributes()
def get_name(self):
return self.ad_group_instance.get_attribute(NAME_ATTRIBUTE)
def get_type(self):
return self.ad_group_instance.get_attribute(TYPE_ATTRIBUTE)
Documentation
-------------
.. code:: python
def get_attribute(attribute_name, no_cache=False):
""" Gets the passed attribute of this group.
:param attribute_name: The name of the attribute to get.
:type attribute_name: str
:param no_cache (optional): Set to True to pull the attribute directly from an LDAP search instead of from the cache. Default False.
:type no_cache: boolean
:returns: The attribute requested or None if the attribute is not set.
"""
def get_attributes(no_cache=False):
""" Returns a dictionary of this group's attributes. This method caches the attributes after the first search unless no_cache is specified.
:param no_cache (optional): Set to True to pull attributes directly from an LDAP search instead of from the cache. Default False
:type no_cache: boolean
"""
def _get_group_members(page_size=500):
""" Searches for a group and retrieve its members.
:param page_size (optional): Many servers have a limit on the number of results that can be returned. Paged searches circumvent that limit. Adjust the page_size to be below the server's size limit. (default: 500)
:type page_size: int
"""
def get_member_info(page_size=500):
""" Retrieves member information from the AD group object.
:param page_size (optional): Many servers have a limit on the number of results that can be returned. Paged searches circumvent that limit. Adjust the page_size to be below the server's size limit. (default: 500)
:type page_size: int
:returns: A dictionary of information on members of the AD group based on the LDAP_GROUPS_ATTRIBUTE_LIST setting or attr_list argument.
"""
def get_tree_members():
""" Retrieves all members from this node of the tree down."""
def add_member(user_lookup_attribute_value):
""" Attempts to add a member to the AD group.
:param user_lookup_attribute_value: The value for the LDAP_GROUPS_USER_LOOKUP_ATTRIBUTE.
:type user_lookup_attribute_value: str
:raises: **AccountDoesNotExist** if the provided account doesn't exist in the active directory. (inherited from _get_user_dn)
:raises: **EntryAlreadyExists** if the account already exists in this group. (subclass of ModificationFailed)
:raises: **InsufficientPermissions** if the bind user does not have permission to modify this group. (subclass of ModificationFailed)
:raises: **ModificationFailed** if the modification could not be performed for an unforseen reason.
"""
def remove_member(user_lookup_attribute_value):
""" Attempts to remove a member from the AD group.
:param user_lookup_attribute_value: The value for the LDAP_GROUPS_USER_LOOKUP_ATTRIBUTE.
:type user_lookup_attribute_value: str
:raises: **AccountDoesNotExist** if the provided account doesn't exist in the active directory. (inherited from _get_user_dn)
:raises: **InsufficientPermissions** if the bind user does not have permission to modify this group. (subclass of ModificationFailed)
:raises: **ModificationFailed** if the modification could not be performed for an unforseen reason.
"""
def add_child(group_lookup_attribute_value):
""" Attempts to add a child to the AD group.
:param group_lookup_attribute_value: The value for the LDAP_GROUPS_GROUP_LOOKUP_ATTRIBUTE.
:type group_lookup_attribute_value: str
:raises: **GroupDoesNotExist** if the provided group doesn't exist in the active directory. (inherited from _get_group_dn)
:raises: **EntryAlreadyExists** if the child already exists in this group. (subclass of ModificationFailed)
:raises: **InsufficientPermissions** if the bind user does not have permission to modify this group. (subclass of ModificationFailed)
:raises: **ModificationFailed** if the modification could not be performed for an unforseen reason.
"""
def remove_child(group_lookup_attribute_value):
""" Attempts to remove a child from the AD group.
:param group_lookup_attribute_value: The value for the LDAP_GROUPS_GROUP_LOOKUP_ATTRIBUTE.
:type group_lookup_attribute_value: str
:raises: **GroupDoesNotExist** if the provided group doesn't exist in the active directory. (inherited from _get_group_dn)
:raises: **EntryAlreadyExists** if the child already exists in this group. (subclass of ModificationFailed)
:raises: **InsufficientPermissions** if the bind user does not have permission to modify this group. (subclass of ModificationFailed)
:raises: **ModificationFailed** if the modification could not be performed for an unforseen reason.
"""
def get_descendants(page_size=500):
""" Returns a list of all descendants of this group.
:param page_size (optional): Many servers have a limit on the number of results that can be returned. Paged searches circumvent that limit. Adjust the page_size to be below the server's size limit. (default: 500)
:type page_size: int
"""
def get_children(page_size=500):
""" Returns a list of this group's children.
:param page_size (optional): Many servers have a limit on the number of results that can be returned. Paged searches circumvent that limit. Adjust the page_size to be below the server's size limit. (default: 500)
:type page_size: int
"""
def child(group_name, page_size=500):
""" Returns the child ad group that matches the provided group_name or none if the child does not exist.
:param group_name: The name of the child group. NOTE: A name does not contain 'CN=' or 'OU='
:type group_name: str
:param page_size (optional): Many servers have a limit on the number of results that can be returned. Paged searches circumvent that limit. Adjust the page_size to be below the server's size limit. (default: 500)
:type page_size: int
"""
def parent():
""" Returns this group's parent (up to the DC)"""
def ancestor(generation):
""" Returns an ancestor of this group given a generation (up to the DC).
:param generation: Determines how far up the path to go. Example: 0 = self, 1 = parent, 2 = grandparent ...
:type generation: int
"""
Running ldap-groups without Django
----------------------------------
If ldap-groups is not used in a django project, the ADGroup object can be initialized with the following parameters:
.. code:: python
ADGroup(group_dn, server_uri, base_dn[, user_lookup_attr[, group_lookup_attr[, attr_list[, bind_dn, bind_password[, user_search_base_dn[, group_search_base_dn]]]]]])
* ``group_dn`` - The distinguished name of the group to manage.
* ``server_uri`` - The ldap server's uri, e.g. 'ldap://example.com'
* ``base_dn`` - The base search dn, e.g. 'DC=example,DC=com'
* ``user_lookup_attr`` - The attribute by which to search when looking up users (should be unique). Defaults to ``'sAMAccountName'``.
* ``group_lookup_attr`` - The attribute by which to search when looking up groups (should be unique). Defaults to ``'name'``.
* ``attr_list`` - A list of attributes returned for each member while pulling group members. An empty list should return all attributes. Defaults to ``['displayName', 'sAMAccountName', 'distinguishedName']``.
* ``bind_dn`` - The bind user's DN
* ``bind_password`` - The bind user's password
* ``user_search_base_dn`` - The base dn to use when looking up users. Defaults to ``LDAP_GROUPS_BASE_DN``.
* ``group_search_base_dn`` - The base dn to use when looking up groups. Defaults to ``LDAP_GROUPS_BASE_DN``.
Running the Tests
------------------
.. code-block:: bash
pip install -r requirements/test.txt
./runtests.py
Changes
=======
4.2.2 (2016-09-14)
------------------
* pep8 and project structure changes
* added support for using ADGroup as a context_manager #2
4.2.1 (2015-12-23)
------------------
* A KeyError is no longer thrown when a member attribute can't be retrieved. None is returned instead. (Thanks @willson556)
4.2.0 (2015-09-01)
------------------
* added get_tree_members method
4.1.1 (2015-08-28)
------------------
* updated dependency, escape_query bugfixes
4.1.0 (2015-03-25)
------------------
* all filter queries are now properly escaped in accordance with the LDAP spec (except the NUL character)
4.0.0 (2014-11-10)
------------------
* added abilily to configure search bases, search for user/group by now specified attribute
* added child add/remove methods, refactored method/class signatures, added attribute caching, all lookups are now paged
3.0.4 (2014-10-20)
------------------
* bugfix, refactoring
3.0.3 (2014-10-13)
------------------
* bugfix
3.0.2 (2014-10-08)
------------------
* bugfix
3.0.1 (2014-10-08)
------------------
* bugfix
3.0.0 (2014-10-03)
------------------
* Switched to python3-ldap
2.5.3 (2014-09-15)
------------------
* Fixed child search, added custom search function
2.5.2 (2014-09-04)
------------------
* Fixed Issue #2, fixed readme examples
2.5.1 (2014-08-31)
------------------
* Fixed python-ldap dependency restriction (now >=)
2.5.0 (2014-08-30)
------------------
* Added group attribute and tree traversal methods
2.0.0 (2014-08-30)
------------------
* Removed django dependency
1.0.1 (2013-09-05)
------------------
* Bugfix - Nonexistent user can also throw a TypeError
1.0.0 (2013-08-26)
------------------
* Initial release
ldap-groups
=============================
A python/django Active Directory group management abstraction that uses ldap3 as a backend for cross-platform compatibility.
Badges
------
.. image:: https://img.shields.io/travis/kavdev/ldap-groups/master.svg?style=flat-square
:target: https://travis-ci.org/kavdev/ldap-groups
.. image:: https://img.shields.io/codecov/c/github/kavdev/ldap-groups/master.svg?style=flat-square
:target: http://codecov.io/github/kavdev/ldap-groups?branch=master
.. image:: https://img.shields.io/requires/github/kavdev/ldap-groups.svg?style=flat-square
:target: https://requires.io/github/kavdev/ldap-groups/requirements/?branch=master
.. image:: https://img.shields.io/codacy/f8b8c71b805e4585b8c34ba7c02fbd0c.svg?style=flat-square
:target: https://www.codacy.com/app/kavdev/ldap-groups/dashboard
.. image:: https://img.shields.io/pypi/v/ldap-groups.svg?style=flat-square
:target: https://pypi.python.org/pypi/ldap-groups
.. image:: https://img.shields.io/pypi/dw/ldap-groups.svg?style=flat-square
:target: https://pypi.python.org/pypi/ldap-groups
.. image:: https://img.shields.io/github/issues/kavdev/ldap-groups.svg?style=flat-square
:target: https://github.com/kavdev/ldap-groups/issues
.. image:: https://img.shields.io/github/license/kavdev/ldap-groups.svg?style=flat-square
:target: https://github.com/kavdev/ldap-groups/blob/master/LICENSE
Installation
-----
Install ldap-groups with pip:
.. code-block:: bash
pip install ldap-groups
Add ldap-groups to ``INSTALLED_APPS`` (if you're using Django)
.. code:: python
INSTALLED_APPS = (
...
'ldap_groups',
...
)
Django Settings
---------------
There are a few settings that must be configured before ldap-groups will run.
*Mandatory*
* ``LDAP_GROUPS_SERVER_URI`` - The ldap server's uri, e.g. 'ldap://example.com'
* ``LDAP_GROUPS_BASE_DN`` - The base search dn, e.g. 'DC=example,DC=com'
*Optional*
* ``LDAP_GROUPS_BIND_DN`` - The bind user's DN
* ``LDAP_GROUPS_BIND_PASSWORD`` - The bind user's password
NOTE: while a bind user is optional, many servers' security settings will deny anonymous access.
* ``LDAP_GROUPS_USER_LOOKUP_ATTRIBUTE`` - The attribute by which to search when looking up users (should be unique). Defaults to ``'sAMAccountName'``.
* ``LDAP_GROUPS_USER_SEARCH_BASE_DN`` - The base dn to use when looking up users. Defaults to ``LDAP_GROUPS_BASE_DN``.
* ``LDAP_GROUPS_GROUP_LOOKUP_ATTRIBUTE`` - The attribute by which to search when looking up groups (should be unique). Defaults to ``'name'``.
* ``LDAP_GROUPS_GROUP_SEARCH_BASE_DN`` - The base dn to use when looking up groups. Defaults to ``LDAP_GROUPS_BASE_DN``.
* ``LDAP_GROUPS_ATTRIBUTE_LIST`` - A list of attributes returned for each member while pulling group members. An empty list should return all attributes. Defaults to ``['displayName', 'sAMAccountName', 'distinguishedName']``.
Usage
-----
In its current state, ldap-groups can perform the following functions:
* Get a specific attribute of a group
* Get all attributes of a group in dictionary form
* Get all members of a group and their attributes (users)
* Add a member to a group (user)
* Remove a member from a group (user)
* Add a child to a group (nested group)
* Remove a child from a group (nested group)
* Get all descendants of a group (groups and organizational units)
* Get all children of a group (groups and organizational units)
* Traverse to a specific child of a group
* Traverse to a group's parent
* Traverse to a group's ancestor
An ADGroup instance only requires one argument to function: a group's distinguished name.
Once the ADGroup is instantiated, the rest is fairly simple:
.. code:: python
from ldap_groups import ADGroup
GROUP_DN = "ou=users,dc=example,dc=com"
ACCOUNT_NAME = "jdoe"
NAME_ATTRIBUTE = "name"
TYPE_ATTRIBUTE = "objectClass"
class ADGroupModifier(object):
def __init__(self):
self.ad_group_instance = ADGroup(GROUP_DN)
def add_member(self):
self.ad_group_instance.add_member(ACCOUNT_NAME)
def remove_member(self):
self.ad_group_instance.remove_member(ACCOUNT_NAME)
def get_group_member_info(self):
return self.ad_group_instance.get_member_info()
class ADGroupInfo(object):
def __init__(self):
self.ad_group_instance = ADGroup(GROUP_DN)
def get_attributes(self):
return self.ad_group_instance.get_attributes()
def get_name(self):
return self.ad_group_instance.get_attribute(NAME_ATTRIBUTE)
def get_type(self):
return self.ad_group_instance.get_attribute(TYPE_ATTRIBUTE)
Documentation
-------------
.. code:: python
def get_attribute(attribute_name, no_cache=False):
""" Gets the passed attribute of this group.
:param attribute_name: The name of the attribute to get.
:type attribute_name: str
:param no_cache (optional): Set to True to pull the attribute directly from an LDAP search instead of from the cache. Default False.
:type no_cache: boolean
:returns: The attribute requested or None if the attribute is not set.
"""
def get_attributes(no_cache=False):
""" Returns a dictionary of this group's attributes. This method caches the attributes after the first search unless no_cache is specified.
:param no_cache (optional): Set to True to pull attributes directly from an LDAP search instead of from the cache. Default False
:type no_cache: boolean
"""
def _get_group_members(page_size=500):
""" Searches for a group and retrieve its members.
:param page_size (optional): Many servers have a limit on the number of results that can be returned. Paged searches circumvent that limit. Adjust the page_size to be below the server's size limit. (default: 500)
:type page_size: int
"""
def get_member_info(page_size=500):
""" Retrieves member information from the AD group object.
:param page_size (optional): Many servers have a limit on the number of results that can be returned. Paged searches circumvent that limit. Adjust the page_size to be below the server's size limit. (default: 500)
:type page_size: int
:returns: A dictionary of information on members of the AD group based on the LDAP_GROUPS_ATTRIBUTE_LIST setting or attr_list argument.
"""
def get_tree_members():
""" Retrieves all members from this node of the tree down."""
def add_member(user_lookup_attribute_value):
""" Attempts to add a member to the AD group.
:param user_lookup_attribute_value: The value for the LDAP_GROUPS_USER_LOOKUP_ATTRIBUTE.
:type user_lookup_attribute_value: str
:raises: **AccountDoesNotExist** if the provided account doesn't exist in the active directory. (inherited from _get_user_dn)
:raises: **EntryAlreadyExists** if the account already exists in this group. (subclass of ModificationFailed)
:raises: **InsufficientPermissions** if the bind user does not have permission to modify this group. (subclass of ModificationFailed)
:raises: **ModificationFailed** if the modification could not be performed for an unforseen reason.
"""
def remove_member(user_lookup_attribute_value):
""" Attempts to remove a member from the AD group.
:param user_lookup_attribute_value: The value for the LDAP_GROUPS_USER_LOOKUP_ATTRIBUTE.
:type user_lookup_attribute_value: str
:raises: **AccountDoesNotExist** if the provided account doesn't exist in the active directory. (inherited from _get_user_dn)
:raises: **InsufficientPermissions** if the bind user does not have permission to modify this group. (subclass of ModificationFailed)
:raises: **ModificationFailed** if the modification could not be performed for an unforseen reason.
"""
def add_child(group_lookup_attribute_value):
""" Attempts to add a child to the AD group.
:param group_lookup_attribute_value: The value for the LDAP_GROUPS_GROUP_LOOKUP_ATTRIBUTE.
:type group_lookup_attribute_value: str
:raises: **GroupDoesNotExist** if the provided group doesn't exist in the active directory. (inherited from _get_group_dn)
:raises: **EntryAlreadyExists** if the child already exists in this group. (subclass of ModificationFailed)
:raises: **InsufficientPermissions** if the bind user does not have permission to modify this group. (subclass of ModificationFailed)
:raises: **ModificationFailed** if the modification could not be performed for an unforseen reason.
"""
def remove_child(group_lookup_attribute_value):
""" Attempts to remove a child from the AD group.
:param group_lookup_attribute_value: The value for the LDAP_GROUPS_GROUP_LOOKUP_ATTRIBUTE.
:type group_lookup_attribute_value: str
:raises: **GroupDoesNotExist** if the provided group doesn't exist in the active directory. (inherited from _get_group_dn)
:raises: **EntryAlreadyExists** if the child already exists in this group. (subclass of ModificationFailed)
:raises: **InsufficientPermissions** if the bind user does not have permission to modify this group. (subclass of ModificationFailed)
:raises: **ModificationFailed** if the modification could not be performed for an unforseen reason.
"""
def get_descendants(page_size=500):
""" Returns a list of all descendants of this group.
:param page_size (optional): Many servers have a limit on the number of results that can be returned. Paged searches circumvent that limit. Adjust the page_size to be below the server's size limit. (default: 500)
:type page_size: int
"""
def get_children(page_size=500):
""" Returns a list of this group's children.
:param page_size (optional): Many servers have a limit on the number of results that can be returned. Paged searches circumvent that limit. Adjust the page_size to be below the server's size limit. (default: 500)
:type page_size: int
"""
def child(group_name, page_size=500):
""" Returns the child ad group that matches the provided group_name or none if the child does not exist.
:param group_name: The name of the child group. NOTE: A name does not contain 'CN=' or 'OU='
:type group_name: str
:param page_size (optional): Many servers have a limit on the number of results that can be returned. Paged searches circumvent that limit. Adjust the page_size to be below the server's size limit. (default: 500)
:type page_size: int
"""
def parent():
""" Returns this group's parent (up to the DC)"""
def ancestor(generation):
""" Returns an ancestor of this group given a generation (up to the DC).
:param generation: Determines how far up the path to go. Example: 0 = self, 1 = parent, 2 = grandparent ...
:type generation: int
"""
Running ldap-groups without Django
----------------------------------
If ldap-groups is not used in a django project, the ADGroup object can be initialized with the following parameters:
.. code:: python
ADGroup(group_dn, server_uri, base_dn[, user_lookup_attr[, group_lookup_attr[, attr_list[, bind_dn, bind_password[, user_search_base_dn[, group_search_base_dn]]]]]])
* ``group_dn`` - The distinguished name of the group to manage.
* ``server_uri`` - The ldap server's uri, e.g. 'ldap://example.com'
* ``base_dn`` - The base search dn, e.g. 'DC=example,DC=com'
* ``user_lookup_attr`` - The attribute by which to search when looking up users (should be unique). Defaults to ``'sAMAccountName'``.
* ``group_lookup_attr`` - The attribute by which to search when looking up groups (should be unique). Defaults to ``'name'``.
* ``attr_list`` - A list of attributes returned for each member while pulling group members. An empty list should return all attributes. Defaults to ``['displayName', 'sAMAccountName', 'distinguishedName']``.
* ``bind_dn`` - The bind user's DN
* ``bind_password`` - The bind user's password
* ``user_search_base_dn`` - The base dn to use when looking up users. Defaults to ``LDAP_GROUPS_BASE_DN``.
* ``group_search_base_dn`` - The base dn to use when looking up groups. Defaults to ``LDAP_GROUPS_BASE_DN``.
Running the Tests
------------------
.. code-block:: bash
pip install -r requirements/test.txt
./runtests.py
Changes
=======
4.2.2 (2016-09-14)
------------------
* pep8 and project structure changes
* added support for using ADGroup as a context_manager #2
4.2.1 (2015-12-23)
------------------
* A KeyError is no longer thrown when a member attribute can't be retrieved. None is returned instead. (Thanks @willson556)
4.2.0 (2015-09-01)
------------------
* added get_tree_members method
4.1.1 (2015-08-28)
------------------
* updated dependency, escape_query bugfixes
4.1.0 (2015-03-25)
------------------
* all filter queries are now properly escaped in accordance with the LDAP spec (except the NUL character)
4.0.0 (2014-11-10)
------------------
* added abilily to configure search bases, search for user/group by now specified attribute
* added child add/remove methods, refactored method/class signatures, added attribute caching, all lookups are now paged
3.0.4 (2014-10-20)
------------------
* bugfix, refactoring
3.0.3 (2014-10-13)
------------------
* bugfix
3.0.2 (2014-10-08)
------------------
* bugfix
3.0.1 (2014-10-08)
------------------
* bugfix
3.0.0 (2014-10-03)
------------------
* Switched to python3-ldap
2.5.3 (2014-09-15)
------------------
* Fixed child search, added custom search function
2.5.2 (2014-09-04)
------------------
* Fixed Issue #2, fixed readme examples
2.5.1 (2014-08-31)
------------------
* Fixed python-ldap dependency restriction (now >=)
2.5.0 (2014-08-30)
------------------
* Added group attribute and tree traversal methods
2.0.0 (2014-08-30)
------------------
* Removed django dependency
1.0.1 (2013-09-05)
------------------
* Bugfix - Nonexistent user can also throw a TypeError
1.0.0 (2013-08-26)
------------------
* Initial release
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
ldap-groups-4.2.2.tar.gz
(15.6 kB
view hashes)
Built Distribution
Close
Hashes for ldap_groups-4.2.2-py2.py3-none-any.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 1af492950f38a2a4a42b669a305a71020936b736adfcfa6108115c578b3bca61 |
|
MD5 | 1d1843f7f0ce30c89c2bfdee1b7f3921 |
|
BLAKE2b-256 | 9162181f70f8e0982080feccf5b4572f838858c3b9454d3493934aa4ab4215cd |