Built-In Extensions

Description Attributes

Support for structured description fields.

This implements the common pattern of storing arbitrary key=value data in description fields, but presents an attribute-like interface to access and change them.

Example:

from laurelin.ldap import LDAP
LDAP.activate_extension('laurelin.extensions.descattrs')

with LDAP() as ldap:
    result = ldap.base.get_child('cn=someObject')

    result.add_desc_attrs({'foo':['one', 'two']})
    print(result.format_ldif())
    # ...
    # description: foo=one
    # description: foo=two
    # ...

    attr_vals = result.desc_attrs().get_attr('foo')
    print(attr_vals)
    # ['one', 'two']

    result.replace_desc_attrs({'foo':['one','two','three']})
    result.delete_desc_attrs({'foo':['two']})

    attr_vals = result.desc_attrs().get_attr('foo')
    print(attr_vals)
    # ['one', 'three']

    print(result.format_ldif())
    # ...
    # description: foo=one
    # description: foo=three
    # ...
class laurelin.ldap.LDAPObject[source]

The following new methods get bound to laurelin.ldap.LDAPObject upon extension activation:

desc_attrs()

Query the description attribute if unknown and return an AttrsDict representing the data stored in the description.

Returns:An AttrsDict representing the data stored in the description.
Return type:AttrsDict
add_desc_attrs(attrs_dict)

Add new description attributes.

Parameters:attrs_dict (dict(str, list[str]) or AttrsDict) – Dictionary of description attributes to add
Return type:None
delete_desc_attrs(attrs_dict)

Delete description attributes.

Parameters:attrs_dict (dict(str, list[str]) or AttrsDict) – Dictionary of description attributes to delete
Return type:None
replace_desc_attrs(attrs_dict)

Replace description attributes.

Parameters:attrs_dict (dict(str, list[str]) or AttrsDict) – Dictionary of description attributes to set
Return type:None

NIS Netgroups

Extension adding netgroup support to laurelin.

Includes schema definitions.

You should begin by tagging the base object which all netgroups are below, and defining the RDN attribute and scope. If the structure is flat there is a performance advantage by setting relative_search_scope=Scope.ONE:

from laurelin.ldap import LDAP, Scope
netgroups_extension = LDAP.activate_extension('laurelin.extensions.netgroups')

with LDAP() as ldap:
    netgroups = ldap.base.obj('ou=netgroups',
                              tag=netgroups_extension.TAG,
                              relative_search_scope=Scope.ONE,
                              rdn_attr='cn')

Member Lists

This extension module allows a shortcut to specify members of netgroups. Any function with a members argument uses this feature.

The function name will tell you whether it expects users (e.g., LDAP.add_netgroup_users()) or hosts (e.g. LDAP.add_netgroup_hosts()). If you just specify a string in your member list, it will be assumed to be either a user or a host accordingly.

You can also specify a tuple with up to 3 elements for any member list entry. These fields must correspond to the nisNetgroupTriple fields: host, user, and domain. For user functions, at least the first 2 tuple elements must be specified. For host functions, only the first is required, the 2nd (user) field will be assumed as an empty string. In all cases, the domain can be specified for all members by passing the domain argument to the function (it defaults to an empty string).

The third option for member list entries is to specify the full nisNetgroupTriple yourself in a string.

Finally, you can specify a memberNisNetgroup by prefixing the entry with a + symbol. For example: +users.

Examples:

users = [
   'alice',
   'bob',
   ('dir.example.org', 'admin'),
   '(dir.example.org,manager,example.org)',
]

ldap.add_netgroup_users('cn=managers,ou=netgroups,dc=example,dc=org', users, domain='example.org')
# Adds the following nisNetgroupTriples:
#  (,alice,example.org)
#  (,bob,example.org)
#  (dir.example.org,admin,example.org)
#  (dir.example.org,manager,example.org)
# Does not add any memberNisNetgroups

hosts = [
    'dir1.example.org',
    'dir2.example.org',
    '(dir3.example.org,,)',
    ('dir4.example.org',),
    '+aws_backup_dir_servers',
]

ldap.add_netgroup_hosts('cn=dir_servers,ou=netgroups,dc=example,dc=org', hosts)
# Adds the following nisNetgroupTriples:
#  (dir1.example.org,,)
#  (dir2.example.org,,)
#  (dir3.example.org,,)
#  (dir4.example.org,,)
# Adds the following memberNisNetgroup:
#  aws_backup_dir_servers
netgroups.TAG = 'netgroup_base'
netgroups.NETGROUP_ATTRS = ['cn', 'nisNetgroupTriple', 'memberNisNetgroup', 'objectClass']
netgroups.OBJECT_CLASS = 'nisNetgroup'
class laurelin.ldap.LDAP[source]

The following new methods get bound to laurelin.ldap.LDAP upon extension activation:

get_netgroup(cn, attrs=NETGROUP_ATTRS)

Find a specific netgroup object.

This depends on the base object having been tagged and configured properly. See laurelin.extensions.netgroups.

Parameters:
  • cn (str) – The name of the group or an RDN
  • attrs (list[str]) – List of attribute names to get. Defaults to all netgroup attributes.
Returns:

The netgroup object

Return type:

LDAPObject

Raises:

TagError – if the base object has not been tagged.

Search for netgroups.

This depends on the base object having been tagged and configured properly. See laurelin.extensions.netgroups.

Parameters:
  • filter (str) – A partial filter string. The nisNetgroup objectClass will automatically be included in the filter sent to the server.
  • attrs (list[str]) – List of attribute names to get. Defaults to all netgroup attributes.
Returns:

An iterator over matching netgroup objects, yielding instances of LDAPObject.

Return type:

SearchResultHandle

Raises:

TagError – if the base object has not been tagged.

get_netgroup_users(cn, recursive=True)

Get a list of all user entries for a netgroup.

This depends on the base object having been tagged and configured properly. See laurelin.extensions.netgroups.

Parameters:
  • cn (str) – The name of the group or an RDN
  • recursive (bool) – Recursively get users by following memberNisNetgroups
Returns:

A list of usernames

Return type:

list[str]

Raises:

TagError – if the base object has not been tagged.

get_netgroup_hosts(cn, recursive=True)

Query a list of all host entries for a netgroup.

This depends on the base object having been tagged and configured properly. See laurelin.extensions.netgroups.

Parameters:
  • cn (str) – The name of the group or an RDN
  • recursive (bool) – Recursively get hosts by following memberNisNetgroups
Returns:

A list of hostnames

Return type:

list[str]

Raises:

TagError – if the base object has not been tagged.

get_netgroup_obj_users(ng_obj, recursive=True)

Get a list of netgroup users from an already queried object, possibly querying for memberNisNetgroups if recursive=True (the default).

Parameters:
  • ng_obj (LDAPObject) – A netgroup LDAP object
  • recursive (bool) – Set to False to only consider members of this group directly
Returns:

A list of usernames

Return type:

list[str]

get_netgroup_obj_hosts(ng_obj, recursive=True)

Get a list of netgroup hosts from an already queried object, possibly querying for memberNisNetgroups if recursive=True (the default).

Parameters:
  • ng_obj (LDAPObject) – A netgroup LDAP object
  • recursive (bool) – Set to False to only consider members of this group directly
Returns:

A list of hostnames

Return type:

list[str]

add_netgroup_users(dn, members, domain='')

Add new users to a netgroup.

Parameters:
  • dn (str) – The absolute DN of the netgroup object
  • members (list or str or tuple) – A Member List (see laurelin.extensions.netgroups doc) or sinlge member list entry
  • domain (str) – The default domain to use in nisNetgroupTriples where not already specified
Return type:

None

add_netgroup_hosts(dn, members, domain='')

Add new hosts to a netgroup.

Parameters:
  • dn (str) – The absolute DN of the netgroup object
  • members (list or str or tuple) – A Member List (see laurelin.extensions.netgroups doc) or single member list entry
  • domain (str) – The default domain to use in nisNetgroupTriples where not already specified
Return type:

None

replace_netgroup_users(dn, members, domain='')

Set new users on a netgroup.

Parameters:
  • dn (str) – The absolute DN of the netgroup object
  • members (list or str or tuple) – A Member List (see laurelin.extensions.netgroups doc) or sinlge member list entry
  • domain (str) – The default domain to use in nisNetgroupTriples where not already specified
Return type:

None

replace_netgroup_hosts(dn, members, domain='')

Set new hosts on a netgroup.

Parameters:
  • dn (str) – The absolute DN of the netgroup object
  • members (list or str or tuple) – A Member List (see laurelin.extensions.netgroups doc) or single member list entry
  • domain (str) – The default domain to use in nisNetgroupTriples where not already specified
Return type:

None

delete_netgroup_users(dn, members, domain='')

Delete users from a netgroup.

Parameters:
  • dn (str) – The absolute DN of the netgroup object
  • members (list or str or tuple) – A Member List (see laurelin.extensions.netgroups doc) or sinlge member list entry
  • domain (str) – The default domain to use in nisNetgroupTriples where not already specified
Return type:

None

delete_netgroup_hosts(dn, members, domain='')

Delete hosts from a netgroup.

Parameters:
  • dn (str) – The absolute DN of the netgroup object
  • members (list or str or tuple) – A Member List (see laurelin.extensions.netgroups doc) or single member list entry
  • domain (str) – The default domain to use in nisNetgroupTriples where not already specified
Return type:

None

class laurelin.ldap.LDAPObject[source]

The following new methods get bound to laurelin.ldap.LDAPObject upon extension activation:

get_netgroup_users(recursive=True)

Get all users in this netgroup object.

Parameters:recursive (bool) – Set to False to ignore any memberNisNetgroups defined for this object.
Returns:A list of usernames
Return type:list[str]
Raises:RuntimeError – if this object is missing the netgroup object class
get_netgroup_hosts(recursive=True)

Get all hosts in this netgroup object.

Parameters:recursive (bool) – Set to False to ignore any memberNisNetgroups defined for this object.
Returns:A list of hostnames
Return type:list[str]
Raises:RuntimeError – if this object is missing the netgroup object class
add_netgroup_users(members, domain='')

Add new user netgroup entries to this netgroup object.

Parameters:
Return type:

None

Raises:

RuntimeError – if this object is missing the netgroup object class

add_netgroup_hosts(members, domain='')

Add new host netgroup entries to this netgroup object.

Parameters:
Return type:

None

Raises:

RuntimeError – if this object is missing the netgroup object class

replace_netgroup_users(members, domain='')

Set new user netgroup entries on this netgroup object.

Parameters:
Return type:

None

Raises:

RuntimeError – if this object is missing the netgroup object class

replace_netgroup_hosts(members, domain='')

Set new host netgroup entries on this netgroup object.

Parameters:
Return type:

None

Raises:

RuntimeError – if this object is missing the netgroup object class

delete_netgroup_users(members, domain='')

Delete user netgroup entries from this netgroup object.

Parameters:
Return type:

None

Raises:

RuntimeError – if this object is missing the netgroup object class

delete_netgroup_hosts(members, domain='')

Delete host netgroup entries from this netgroup object.

Parameters:
Return type:

None

Raises:

RuntimeError – if this object is missing the netgroup object class

Paged Results

RFC 2696 Simple Paged Results Manipulation

This adds a control to support paging results. Use the control keyword paged with search methods. Returns a cookie on the page_cookie response attribute which can be found on the results handle after all paged results have been received. See example below.

Note: Do not use this extension to simply limit the total number of results. The search methods accept a limit keyword out of the box for this purpose.

Example usage:

from laurelin.ldap import LDAP
LDAP.activate_extension('laurelin.extensions.pagedresults')

with LDAP() as ldap:
    search = ldap.base.search(paged=10)
    page1_results = list(search)

    search = ldap.base.search(paged=(10, search.page_cookie))
    page2_results = list(search)

    # ...

    if not search.page_cookie:
        print('Got all pages')

Note: When getting pages in a loop, you may set the cookie value to an empty string on the first iteration, e.g.:

ldap.base.search(paged=(10, ''))