Laurelin Python LDAP Client¶
Laurelin is a pure-Python ORM-esque LDAP client. Check out the user docs to get started. View the source on GitHub.
User Docs¶
Features Overview¶
- Fully compliant with RFC 4510 and its children.
- Pure Python codebase, meaning that it can be used with Python implementations other than CPython.
- Tested against CPython 2.7, 3.3, 3.4, 3.5, 3.6, PyPy, and PyPy3.
- Simplified filter syntax (optional, standard filter syntax is fully supported and used by default)
- Pythonic attributes input and presentation. It’s just a dictionary.
- Exceedingly easy relative searching. All objects have a suite of search methods which will automatically pass the object’s DN as the search base. In many cases, you wont have to pass any arguments to search methods.
- Similarly, all objects have a suite of modify methods which allow you to change attributes on already-queried objects without having to pass their DN again.
- Intelligent modification will never send existing attribute values to the server, nor will it request deletion of attribute values that do not exist. This prevents many unnecessary server errors. Laurelin will go as far as to query the object for you before modifying it to ensure you don’t see pointless errors (if you want it to).
- Custom validation. You can define validators which check new objects and modify operations for correctness before sending them to the server. Since you control this code, this can be anything from a simple regex check against a particular attribute value, to a complex approval queue mechanism.
- Highly extensible. New methods can easily and safely be bound to base classes.
- Seamless integration of controls. Once defined, these are just new keyword arguments on particular methods, and additional attributes on the response object.
- Includes Python implementations of standard schema elements. This conveys many benefits:
- Allows changes to be validated before sending the server
- Allows matching rules to be used to compare attribute values locally. Many attribute types are case-insensitive and
have other rules meaning that the standard Python
==
orin
operators won’t tell you what you want to know. Laurelin makes them work according to these rules.
Missing/incomplete features¶
Some lesser-used features of the LDAP protocol have not yet been implemented or are incomplete. Check the GitHub issues to see if your use case is affected. Please add a comment if so, or open a new issue if you spot anything else. PRs are always welcome.
Walkthrough¶
Note
I’m assuming that if you’re here, you’re already pretty familiar with LDAP fundamentals. If you don’t know how to write a search filter, you may want to do some more reading on LDAP before continuing.
Getting Started¶
The first thing you should typically do after importing is configure logging and/or warnings. There is a lot of useful information available at all log levels:
from laurelin.ldap import LDAP
LDAP.enable_logging()
# Enables all log output on stderr
# It also accepts an optional log level argument, e.g. LDAP.enable_logging(logging.ERROR)
# The function also returns the handler it creates for optional further manual handling
import logging
logger = logging.getLogger('laurelin.ldap')
# Manually configure the logger and handlers here using the standard logging module
# Submodules use the logger matching their name, below laurelin.ldap
LDAP.log_warnings()
# emit all LDAP warnings as WARN-level log messages on the laurelin.ldap logger
# all other warnings will take the default action
LDAP.disable_warnings()
# do not emit any LDAP warnings
# all other warnings will take the default action
You can then initialize a connection to an LDAP server. Pass a URI string to the LDAP
constructor:
with LDAP('ldap://dir.example.org:389') as ldap:
# do stuff...
# Its also possible, but not reccommended, to not use the context manager:
ldap = LDAP('ldap://dir.example.org:389')
This will open a connection and query the server to find the “base DN” or DN suffix. An empty LDAPObject
will
be created with the base DN and stored as the base
attribute on the LDAP
instance. More on this later. For
now we will briefly cover the basic LDAP interface which may seem somewhat familiar if you have used the standard
python-ldap client before.
LDAP Methods Intro¶
LDAP.search()
sends a search request and returns an iterable over instances of LDAPObject
. Basic
arguments are described here (listed in order):
base_dn
- the absolute DN to start the search fromscope
- One of:
Scope.BASE
- only searchbase_dn
itselfScope.ONE
- searchbase_dn
and its immediate childrenScope.SUB
- searchbase_dn
and all of its descendents (default)filter
- standard LDAP filter stringattrs
- a list of attributes to return for each object
Use LDAP.get()
if you just need to get a single object by its DN. Also accepts an optional list of attributes.
LDAP.add()
adds a new object, and returns the corresponding LDAPObject
, just pass the full, absolute
DN and an attributes dict
LDAP.delete()
deletes an entire object. Just pass the full, absolute DN of the object to delete.
The following methods are preferred for modification, however raw modify methods are also provided.
All accept the absolute DN of the object to modify, and an attributes dictionary.
LDAP.add_attrs()
adds new attributes.
LDAP.delete_attrs()
deletes attribute values. Pass an empty values list in the attributes dictionary to delete
all values for an attribute.
LDAP.replace_attrs()
replaces all values for the given attributes with the values passed in the attributes
dictionary. Atrributes that are not mentioned are not touched. Passing an empty list removes all values.
For LDAP.delete_attrs()
and LDAP.replace_attrs()
you can specify the constant LDAP.DELETE_ALL
in
place of an empty attribute value list to remove all values for the attribute. For example:
ldap.replace_attrs('cn=foo,dc=example,dc=org', {'someAttribute': LDAP.DELETE_ALL})
If you wish to require the use of the constant instead of an empty list, pass error_empty_list=True
to the
LDAP
constructor. You can also pass ignore_empty_list=True
to silently prevent these from being sent to
the server (this will be the default behavior in a future release).
LDAPObject Methods Intro¶
Great, right? But specifying absolute DNs all the time is no fun. Enter LDAPObject
, and keep in mind the
base
attribute mentioned earlier.
LDAPObject
inherits from AttrsDict
to present attributes. This interface is documented
here.
LDAPObject
defines methods corresponding to all of the LDAP
methods, but pass the object’s dn
automatically, or only require the RDN prefix, with the object’s dn
automatically appended to obtain the absolute
DN.
LDAPObject.search()
accepts all the same arguments as LDAP.search()
except base_dn
and scope
.
The object’s own DN is always used for base_dn
, and the relative_search_scope
is always used as the scope
.
LDAPObject.find()
is more or less a better LDAPObject.get_child()
. It looks at the object’s
relative_search_scope
property to determine the most efficient way to find a single object below this one. It will
either do a BASE search if relative_seach_scope=Scope.ONE
or a SUBTREE search if
relative_search_Scope=Scope.SUB
. It is an error to use this method if relative_search_scope=Scope.BASE
.
LDAPObject.get_child()
is analagous to LDAP.get()
but it only needs the RDN, appending the object’s own DN
as mentioned earlier. (Note that LDAPObject.get()
inherits from the native dict.get()
)
LDAPObject.add_child()
is analagous to LDAP.add()
again accepting an RDN in place of a full absolute DN.
Use LDAPObject.get_attr()
like dict.get()
except an empty list will always be returned as default if the
attribute is not defined.
LDAPObject
’s modify methods update the server first, then update the local attributes dictionary to match if
successful. LDAPObject.add_attrs()
, LDAPObject.delete_attrs()
, and LDAPObject.replace_attrs()
require only a new attributes dictionary as an argument, of the same format as for the matching LDAP
methods.
LDAPObject
Examples:
people = ldap.base.get_child('ou=people')
print(people['objectClass'])
# ['top', 'organizationalUnit']
people.add_attrs({'description':['Contains all users']})
# list all users
for user in people.search(filter='(objectClass=posixAccount)'):
print(user['uid'][0])
Relative Searching¶
All objects have LDAPObject.search()
and LDAPObject.find()
methods which utilize the
relative_search_scope
attribute of the object. relative_search_scope
can be passed as a keyword to any method
that creates new objects, including LDAP.obj()
, LDAP.get()
, LDAP.search()
, LDAP.add()
,
LDAPObject.obj()
, LDAPObject.find()
, LDAPObject.search()
, LDAPObject.get_child()
, and
LDAPObject.add_child()
.
When you create an object from another LDAPObject
and you don’t specify the relative_search_scope
, it is
automatically inherited from the parent object. When you create an object from an LDAP
method, it defaults to
Scope.SUB
.
The real win with this feature is when your tree is structured such that you can set this to Scope.ONE
as this
conveys significant performance benefits, especially when using LDAPObject.find()
. This allows laurelin to
to construct the absolute DN of the child object and perform a highly efficient BASE search.
Attributes Dictionaries¶
This common interface is used both for input and output of LDAP attributes. In short: dict keys are attribute names, and
dict values are a list
of attribute values. For example:
{
'objectClass': ['posixAccount', 'inetOrgPerson'],
'uid': ['ashafer01'],
'uidNumber': ['1000'],
'gidNumber': ['100'],
'cn': ['Alex Shafer'],
'homeDirectory': ['/home/ashafer01'],
'loginShell': ['/bin/zsh'],
'mail': ['ashafer01@example.org'],
}
Note that there is an AttrsDict
class defined - there is no requirement to create instances of this class
to pass as arguments, though you are welcome to if you find the additional methods provided this class convenient, such
as AttrsDict.get_attr()
. Further, it overrides dict
special methods to enforce type requirements and enable
case-insensitive keys.
Also note that when passing an attributes dictionary to LDAP.replace_attrs()
or LDAP.delete_attrs()
it is
legal to specify the constant LDAP.DELETE_ALL
in place of a value list.
Modify Operations¶
Raw modify methods¶
LDAP.modify()
and LDAPObject.modify()
work similarly to the modify functions in python-ldap, which in turn
very closely align with how modify operations are described at the protocol level. A list of Mod
instances is
required with 3 arguments:
- One of the
Mod
constants which describe the operation to perform on an attribute:
Mod.ADD
adds new attributes/valuesMod.REPLACE
replaces all values for an attribute, creating new attributes if necessaryMod.DELETE
removes attributes/values.
- The name of the attribute to modify. Each entry may only modify one attribute, but an unlimited number of entries may be specified in a single modify operation.
- A list of attribute values to use with the modify operation or the constant
LDAP.DELETE_ALL
:
- The list may be empty for
Mod.REPLACE
andMod.DELETE
, both of which will cause all values for the given attribute to be removed from the object. The list may not be empty forMod.ADD
. You can also specify the constantLDAP.DELETE_ALL
in place of any empty list. If you wish to warn about empty lists or require the use of the constant, passwarn_empty_list=True
orerror_empty_list=True
to theLDAP
constructor. You can also passignore_empty_list=True
to silently prevent these from being sent to the server (this will be the default behavior in a future release).- A non-empty list for
Mod.ADD
lists all new attribute values to add- A non-empty list for
Mod.DELETE
lists specific attribute values to remove- A non-empty list for
Mod.REPLACE
indicates ALL new values for the attribute - all others will be removed.
Example custom modify operation:
from laurelin.ldap.modify import Mod
ldap.modify('uid=ashafer01,ou=people,dc=example,dc=org', [
Mod(Mod.ADD, 'mobile', ['+1 401 555 1234', '+1 403 555 4321']),
Mod(Mod.ADD, 'homePhone', ['+1 404 555 6789']),
Mod(Mod.REPLACE, 'homeDirectory', ['/export/home/ashafer01']),
])
Using an LDAPObject
instead:
ldap.base.obj('uid=ashafer01,ou=people').modify([
Mod(Mod.DELETE, 'mobile', ['+1 401 555 1234']),
Mod(Mod.DELETE, 'homePhone', LDAP.DELETE_ALL), # delete all homePhone values
])
Again, an arbitrary number of Mod
entries may be specified for each modify
call.
Strict modification and higher-level modify functions¶
The higher-level modify functions (add_attrs
, delete_attrs
, and replace_attrs
) all rely on the concept of
strict modification - that is, to only send the modify operation, and to never perform an additional search. By
default, strict modification is disabled, meaning that, if necessary, an extra search will be performed before
sending a modify request.
You can enable strict modification by passing strict_modify=True
to the LDAP
constructor.
With strict modification disabled, the LDAP
modify functions will engage a more intelligent modification
strategy after performing the extra query: for LDAP.add_attrs()
, no duplicate values are sent to the server to be
added. Likewise for LDAP.delete_attrs()
, deletion will not be requested for values that are not known to exist.
This prevents many unnecessary failures, as ultimately the final semantic state of the object is unchanged with or
without such failures. (Note that with LDAP.replace_attrs()
no such failures are possible)
With the LDAPObject
modify functions, the situaiton is slightly more complex. Regardless of the
strict_modify
setting, the more intelligent modify strategy will always be used, using at least any already-queried
attribute data stored with the object (which could be complete data depending on how the object was originally
obtained). If strict_modify
is disabled, however, another search may still be performed to fill in any missing
attributes that are mentioned in the passed attributes dict.
The raw modify
functions on both LDAP
and LDAPObject
are unaffected by the strict_modify
setting - they will always attempt the modify operation exactly as specified.
Global Defaults, LDAP instance attributes, and LDAP constructor arguments¶
All of the LDAP
constructor arguments are set to None by default. In the constructor, any explicitly
is None
arguments are set to their associated global default. These are attributes of the LDAP
class, have
the same name as the argument, upper-cased, and with a DEFAULT_
prefix (but the prefix wont be repeated).
For example, the server
argument has global default LDAP.DEFAULT_SERVER
, and default_criticality
is
LDAP.DEFAULT_CRITICALITY
.
Most arguments also have an associated instance property. A complete table is below:
Global Default | LDAP instance attribute |
LDAP constructor keyword |
---|---|---|
LDAP.DEFAULT_SERVER |
host_uri |
server |
LDAP.DEFAULT_BASE_DN |
base_dn |
base_dn |
LDAP.DEFAULT_FILTER |
none | none |
LDAP.DEFAULT_DEREF_ALIASES |
default_deref_aliases |
deref_aliases |
LDAP.DEFAULT_SEARCH_TIMEOUT |
default_search_timeout |
search_timeout |
LDAP.DEFAULT_CONNECT_TIMEOUT |
sock_params[0] |
connect_timeout |
LDAP.DEFAULT_STRICT_MODIFY |
strict_modify |
strict_modify |
LDAP.DEFAULT_REUSE_CONNECTION |
none | reuse_connection |
LDAP.DEFAULT_SSL_VERIFY |
ssl_verify |
ssl_verify |
LDAP.DEFAULT_SSL_CA_FILE |
ssl_ca_file |
ssl_ca_file |
LDAP.DEFAULT_SSL_CA_PATH |
ssl_ca_path |
ssl_ca_path |
LDAP.DEFAULT_SSL_CA_DATA |
ssl_ca_data |
ssl_ca_data |
LDAP.DEFAULT_FETCH_RESULT_REFS |
default_fetch_result_refs |
fetch_result_refs |
LDAP.DEFAULT_FOLLOW_REFERRALS |
default_follow_referrals |
follow_referrals |
LDAP.DEFAULT_SASL_MECH |
default_sasl_mech |
default_sasl_mech |
LDAP.DEFAULT_SASL_FATAL_DOWNGRADE_CHECK |
sasl_fatal_downgrade_check |
sasl_fatal_downgrade_check |
LDAP.DEFAULT_CRITICALITY |
default_criticality |
default_criticality |
LDAP.DEFAULT_VALIDATORS |
validators |
validators |
LDAP.DEFAULT_WARN_EMPTY_LIST |
warn_empty_list |
warn_empty_list |
LDAP.DEFAULT_ERROR_EMPTY_LIST |
error_empty_list |
error_empty_list |
LDAP.DEFAULT_IGNORE_EMPTY_LIST |
ignore_empty_list |
ignore_empty_list |
LDAP.DEFAULT_FILTER_SYNTAX |
default_filter_syntax |
filter_syntax |
LDAP.DEFAULT_BUILT_IN_EXTENSIONS_ONLY` |
none public | built_in_extensions_only |
The LDAP
instance attributes beginning with default_
are used as the defaults for corresponding arguments
on other methods. default_sasl_mech
is used with LDAP.sasl_bind()
, default_criticality
is the default
criticality of all controls, the other default_
attributes are used with LDAP.search()
.
The ssl_
prefixed instances attributes are used as the defaults for LDAP.start_tls()
, as well as the socket
configuration when connecting to an ldaps://
socket.
Basic usage examples¶
1. Connect to local LDAP instance and iterate all objects¶
from laurelin.ldap import LDAP with LDAP('ldapi:///') as ldap: ldap.sasl_bind() for obj in ldap.base.search(): print(obj.format_ldif())
LDAP.sasl_bind()
defaults to the EXTERNAL
mechanism when an ldapi:
URI is given, which uses the current
user for authorization via the unix socket (Known as “autobind” with 389 Directory Server)
Simple Search Filters¶
Laurelin provides an alternate syntax for search filters that is much simpler than the standard, RFC 4515-compliant, filter syntax. In short, it is a hybrid between SQL logic expressions and standard LDAP filter comparisons.
In the simplest case of a single comparison, the two syntaxes are identical:
Standard | Simple |
---|---|
(gidNumber=100) |
(gidNumber=100) |
But when it comes to expressing logic, the Laurelin simplified filter differs quite a bit:
Standard | Simple |
---|---|
(&(gidNumber<=1000)(!(memberUid=*))) |
(gidNumber<=1000) AND NOT (memberUid=*) |
Feel free to include parentheses in your simple filters if it helps clarify the logic:
Simple (without extra parens) | Simple (equivalent with extra parens) |
---|---|
(gidNumber<=1000) AND NOT (memberUid=*) |
(gidNumber<=1000) AND (NOT (memberUid=*)) |
Some more equivalent standard and simple filters:
Standard | Simple |
---|---|
(&(abc=foo)(|(def=bar)(ghi=jkl))) |
(abc=foo) AND ((def=bar) OR (ghi=jkl)) |
(|(abc=foo)(&(def=bar)(ghi=jkl))) |
(abc=foo) OR (def=bar) AND (ghi=jkl) |
(&(abc=foo)(|(def=bar)(ghi=jkl))(xyz=abc)) |
(abc=foo) AND ((def=bar) OR (ghi=jkl)) AND (xyz=abc) |
By default, Laurelin will interpret your filters with the unified filter syntax, meaning you can embed a full RFC 4515-compliant filter anywhere you see a simple comparison in the above examples. This includes as the only element in the filter, making this fully backwards compatible with RFC 4515 standard filters.
Currently available syntaxes are FilterSyntax.STANDARD
to limit to RFC 4515, FilterSyntax.SIMPLE
to limit to
only simple comparisons within SQL-style logic, and the default FilterSyntax.UNIFIED
.
If you wish to restrict the syntax, you can do one of the following:
Pass
filter_syntax=
toLDAP.search()
or any othersearch
method:from laurelin.ldap import LDAP, FilterSyntax with LDAP() as ldap: search = ldap.search('o=foo', filter='(abc=foo) AND (def=bar)', filter_syntax=FilterSyntax.SIMPLE)
Pass
filter_syntax=
to theLDAP
constructor:from laurelin.ldap import LDAP, FilterSyntax with LDAP(filter_syntax=FilterSyntax.SIMPLE) as ldap: search1 = ldap.search('o=foo', filter='(abc=foo) AND (def=bar)') search2 = ldap.search('o=bar', filter='(xyz=foo) OR (abc=bar)')
Set the global default
LDAP.DEFAULT_FILTER_SYNTAX
before instantiating anyLDAP
instances:from laurelin.ldap import LDAP, FilterSyntax LDAP.DEFAULT_FILTER_SYNTAX = FilterSyntax.STANDARD with LDAP() as ldap: search = ldap.search('o=foo', filter='(&(abc=foo)(def=bar))') with LDAP('ldap://localhost:10389') as ldap: search = ldap.search('o=bar', filter='(|(xyz=foo)(abc=bar))')
Do either of the two above using Config Files.
Note
How is this possible?
Doesn’t the filter get sent to the server and parsed there like SQL? No! In LDAP, it is up to the client to parse the filter string into a set of objects that are encoded and sent to the server. If you’ve got any other ideas for alternate filter syntaxes, please submit a PR!
Extensions¶
The following class documents show names of available extensions on different instances.
Laurelin Extensions¶
Every defined extension has a property in this class. An instance is accessible at laurelin.ldap.extensions
.
For example, to require the base schema:
from laurelin.ldap import extensions
extensions.base_schema.require()
-
class
laurelin.ldap.extensible.laurelin_extensions.
Extensions
[source]¶ Bases:
laurelin.ldap.extensible.base.ExtensionsBase
-
base_schema
¶ The standard base schema from various RFCs
Return type: laurelin.extensions.base_schema.LaurelinExtension
-
descattrs
¶ The built-in description attributes extension
Return type: laurelin.extensions.descattrs.LaurelinExtension
-
netgroups
¶ The built-in NIS netgroups extension
Return type: laurelin.extensions.netgroups.LaurelinExtension
-
paged_results
¶ Built-in extension defining standard paged results control for search
Return type: laurelin.extensions.pagedresults.LaurelinExtension
-
LDAP Extensions¶
These properties are available on LDAP
instances.
-
class
laurelin.ldap.extensible.ldap_extensions.
LDAPExtensions
[source]¶ Bases:
laurelin.ldap.extensible.base.ExtensibleClass
-
netgroups
¶ The built-in NIS netgroups extension
Return type: laurelin.extensions.netgroups.LaurelinLDAPExtension
-
LDAPObject Extensions¶
These properties are available on LDAPObject
instances.
-
class
laurelin.ldap.extensible.ldapobject_extensions.
LDAPObjectExtensions
[source]¶ Bases:
laurelin.ldap.extensible.base.ExtensibleClass
-
descattrs
¶ The built-in description attributes extension
Return type: laurelin.extensions.descattrs.LaurelinLDAPObjectExtension
-
netgroups
¶ The built-in NIS netgroups extension
Return type: laurelin.extensions.netgroups.LaurelinLDAPObjectExtension
-
Config Files¶
Intro¶
Laurelin config files may be YAML or JSON formatted out of the box. You can also supply your own custom decoding function to handle arbitrary formats. The important part is that the file contents decode to a dictionary. Below is an example YAML file:
global:
SSL_CA_PATH: /etc/ldap/cacerts
IGNORE_EMPTY_LIST: true
extensions:
- laurelin.extensions.descattrs
- laurelin.extensions.netgroups
connection:
server: ldap://dir01.example.org
start_tls: true
simple_bind:
username: testuser
passowrd: testpassword
connect_timeout: 30
objects:
- rdn: ou=people
tag: posix_user_base
- rdn: ou=groups
tag: posix_group_base
- rdn: ou=netgroups
tag: netgroup_base
You can load and apply such a file by using config.load_file()
. If a connection
section was specified, a new
connection will be established and returned from the function.
Global Section¶
Each key in the global section must correspond to one of the DEFAULT_
prefixed attributes on LDAP
. As you
can see in the example, the DEFAULT_
prefix is optional. Not demonstrated by the example is that keys are
case-insensitive (that is, they will be upper-cased for you).
Extensions Section¶
This is simply a list of extension module names which will get activated when the config file is loaded.
Connection Section¶
Keys here are mostly corresponding to LDAP
constructor arguments, however there are a few special ones:
start_tls
A boolean option, if set totrue
will executeLDAP.start_tls()
after opening the connectionsimple_bind
A dictionary of parameters to pass toLDAP.simple_bind()
sasl_bind
A dictionary of parameters to pass toLDAP.sasl_bind()
Note that simple_bind
and sasl_bind
are both optional, and mutually exclude each other. In other words, it is an
error to specify both of these keys.
Note that start_tls
will always occur before any bind (if requested).
Objects Section¶
Note
You cannot specify objects
without also specifying a connection
This is a list of dicts where keys correspond to LDAP.obj()
or LDAPObject.obj()
arguments. You must
specify exactly one of dn
or rdn
. If dn
is specified, this will be taken as the full, absolute DN of the
object, and parameters will be passed to LDAP.obj()
. If rdn
is specified, this will be taken as the RDN
relative to the connection’s base object, or the base of the tree, and parameters will be passed to
LDAPObject.obj()
.
Also required for all objects is the tag
key. This is how you will access created objects. For example, to access
the first object in the config file example above:
ldap = config.load_file('/path/to/file.yaml')
posix_users = ldap.tag('posix_user_base')
Its important to note that the server is not queried when creating these objects, so they will not have any local
attributes. If you require local attributes, you can all LDAPObject.refresh()
on the object.
Global vs. Connection¶
As mentioned elsewhere in the docs, there is a global config parameter associated with every connection parameter,
meaning in a config file you can define your connection parameters in either section. This does not have the exact
same end functionality, though. In general you should prefer connection
for the following reasons:
- The connection will not be created when the config file is loaded if you configure everything in
global
- You cannot define
objects
without defining aconnection
- You cannot specify
start_tls
or bind parameters globally
However there are cases where it may be desirable to specify everything as a global default. Taking this approach allows
you to use the LDAP
constructor with as few as zero arguments after loading the config. You can still bind as
usual by calling LDAP.simple_bind()
or LDAP.sasl_bind()
on the connection. You can also manually create
objects with obj()
methods.
Load Order¶
Sections are loaded and applied in a specific order:
global
extensions
connection
objects
You can specify sections in whatever order is convenient in your file. They will always be used in the above order.
Using Dicts Directly¶
If you already have your configuration parameters in one or more dictionaries, you can apply them directly without
going through the file interface. You can pass a dictionary of the same format as in a config file to
config.load_config_dict()
. Like load_file()
, this will establish and return the new connection if one was
defined.
You can also use the other config
methods to apply dictionary configurations piecemeal. These process fragments
of the larger config dictionary. Check the reference docs for details if you need to do this.
Creating Extensions¶
The most important thing to note about “extensions” is that they are not necessarily LDAP extensions. In laurelin, they
are simply a module that does any combination of: defining new schema elements, defining new controls, or defining new
methods to be attached to LDAP
or LDAPObject
.
Extension System¶
Extensions live in any importable module or package. They must at minimum define a class called LaurelinExtension
as
follows:
from laurelin.ldap import BaseLaurelinExtension
class LaurelinExtension(BaseLaurelinExtension):
NAME = 'some_name'
You’ll notice the BaseLaurelinExtension
here - this is required. It is one of many weapons at your disposal.
Extension Classes¶
All of these share the same common end-user interface of being exposed as either a property or dynamic attribute on some other instance that the user typically will already use normally. Which class they are attached to depends on the name and base class of the defined extension class. Whether they are accessible as a property (with IDE auto-complete support) or a dynamic attribute depends on how the extension is loaded and defined (more below), but the user API is unchanged either way.
class LaurelinExtension(
BaseLaurelinExtension
):
- As described above, this is where you define the name of the property or dynamic attribute where all instances of
these extension classes can be accessed. One instance of this class is created per Python interpreter when the
extesion is first added or used (more on this later) and it is accessible to users at
laurelin.ldap.extensions.<NAME>
. class LaurelinLDAPExtension(
BaseLaurelinLDAPExtension
):
- This is where you can bind methods, attributes, etc. that will be attached to
LDAP
by way of property or dynamic attribute with name corresponding to yourLaurelinExtension.NAME
. You can access the parentLDAP
instance atself.parent
. Up to one instance is created perLDAP
instance when the property or dynamic attribute is first accessed on a particular instance. class LaurelinLDAPObjectExtension(
BaseLaurelinLDAPObjectExtension
):
- This is where you can bind methods, attributes, etc. that will be attached to
LDAPObject
by way of property or dynamic attribute with name corresponding to yourLaurelinExtension.NAME
. You can access the parentLDAPObject
instance atself.parent
. Up to once instance is created perLDAPObject
instance when the property or dynamic attribute is first accessed on a particular instance.
Schema and Controls Classes¶
These two simply attempt to register all public attributes defined within them as schema elements or controls. More about actually defining these below, the class signatures should look like this, though:
class LaurelinSchema(
BaseLaurelinSchema
):
- Define all
SyntaxRule
andEqualityMatchingRule
classes as local classes within this class. Directly instantiateObjectClass
andAttributeType
with standard spec strings and assign them to class attributes. class LaurelinControls(
BaseLaurelinControls
):
- Define all
Control
classes as local classes within this class.
Note that the placement of schema and control definitions is fairly flexible and are not restricted to these 2 classes (but this kind of organization or a variation upon it is suggested). See the Schema and Controls sections below for more details.
Also note that if your schema depends on the base schema, you must require it at the top of your extension like so:
from laurelin.ldap import extensions
extensions.base_schema.require()
Depending on Extensions¶
Extension authors may want to duplicate and tailor some or all of this information in their own documentation for users.
There are two ways laurelin can be made aware of extensions:
- By passing a module name string to
add_extension()
. This will cause the extension class instances to be made available as dynamic attributes. - By being defined in
Extensible.AVAILABLE_EXTENSIONS
. A script will automatically generate properties that are inherited by the appropriate parent class (LDAP
orLDAPObject
). This has the benefit that IDEs can auto-complete extension instances if the extension is installed (tested with PyCharm). Also defined with your extension is the string module name, so your users do not need to copy this themselves, as well as the pip package name, which will be included in the exception if users attempt to use your extension when its not installed.
There are clear pros and cons to each approach, and extension authors are welcome to instruct users to take either approach. #1 may be preferred during development, or if you do not intend to publish your extension publicly.
One caveat to #2 above if you define schema or controls, is your users will need to explicitly require your extension like so:
from laurelin.ldap import extensions
extensions.<NAME>.require()
This happens implicitly in the following situations:
- When
add_extension()
is called, as in #1 above - When the user accesses your
<NAME>
extension property/attribute onLDAP
orLDAPObject
, if you defined any extensions to those classes - Technically happens implicitly when
extensions.<NAME>
is accessed, so if you define any other user-exposed attributes on yourLaurelinExtension
class that all users must access, you can instruct them to use that instead.
So if you require any of these of your users by way of your own documentation, you can also have them skip the
explicit require()
call.
Regardless of whether your extension is added or defined, your users will need to explicitly add the dependency to their own package. Laurelin will never depend on an extension module, and only built-in extensions are guarnateed to be available.
Publishing Extensions¶
If you are planning on defining any standard LDAP extensions, schema, or controls, I suggest packaging your module under
laurelin.extensions
, which is a
namespace package. This allows an
exceedingly simple and easy path to eventual merging in as a built-in extension. You are welcome to package under
any importable module, though.
If you choose to instruct your users to add your extension, please be sure to write clear and accessible documentation for them.
If you choose to define your extension, please submit a pull request on GitHub. You should include ONLY a ~5 line
addition to Extensible.AVAILABLE_EXTENSIONS
. The dict key should match your LaurelinExtension.NAME
.
The keys in the sub-dictionary should be pretty self-explanatory. Below is a contrived example patch:
diff --git a/laurelin/ldap/extensible/base.py b/laurelin/ldap/extensible/base.py
index 593e64b..bd7b233 100644
--- a/laurelin/ldap/extensible/base.py
+++ b/laurelin/ldap/extensible/base.py
@@ -132,6 +132,11 @@ class Extensible(object):
'pip_package': None, # built-in
'docstring': 'Built-in extension defining standard paged results control for search'
},
+ 'some_ext': {
+ 'module': 'your.extension.module',
+ 'pip_package': 'laurelin-some-ext',
+ 'docstring': 'A contrived example laurelin extension'
+ },
}
ADDITIONAL_EXTENSIONS = {}
Please keep your docstrings short. They will be rendered in laurelin’s documentation. You may include a Sphinx-formatted shortlink to your own docs.
If you have any questions, problems, or concerns, please open an issue on GitHub.
LDAP Extensions¶
When defining an actual LDAP extension with an OID and requiring server support, you’ll create the laurelin extension as
shown above, but you’ll be calling the LDAP.send_extended_request()
method from your extension methods within
your LaurelinLDAPExtension
or LaurelinLDAPObjectExtension
.
-
LDAP.
send_extended_request
(oid, value=None, **kwds)[source] Send an extended request, returns instance of
ExtendedResponseHandle
This is mainly meant to be called by other built-in methods and client extensions. Requires handling of raw pyasn1 protocol objects.
Parameters: Returns: An iterator yielding tuples of the form (
rfc4511.IntermediateResponse
,rfc4511.Controls
) or (rfc4511.ExtendedResponse
,rfc4511.Controls
).Return type: Raises: - LDAPSupportError – if the OID is not listed in the supportedExtension attribute of the root DSE
- TypeError – if the value parameter is not a valid type
Additional keyword arguments are handled as Controls and then passed through into the
ExtendedResponseHandle
constructor.
As you can see, this accepts the OID of the LDAP extension and an optional request value. You can also pass control
keywords, and the require_success
keyword, which will automatically check for success on the final extendedResponse
message (and raise an LDAPError
on failure).
If your LDAP extension expects intermediateResponse messages, you can iterate the return from
LDAP.send_extended_request()
. You can also call ExtendedResponseHandle.recv_response()
to get only one
message at a time (preferred to iteration if you only expect the one extendedResponse message).
The built-in LDAP.who_am_i()
method is an excellent example of a simple LDAP extension:
from laurelin.ldap import LDAP
from laurelin.ldap.protoutils import get_string_component
def who_am_i(self):
handle = self.send_extended_request(LDAP.OID_WHOAMI, require_success=True, **ctrl_kwds)
xr, res_ctrls = handle.recv_response()
return get_string_component(xr, 'responseValue')
As a laurelin extension this might look like:
from laurelin.ldap import BaseLaurelinLDAPExtension
# ...
class LaurelinLDAPExtension(BaseLaurelinLDAPExtension):
def who_am_i(self):
handle = self.parent.send_extended_request(...)
# ...
Note the use of self.parent
to access LDAP.send_extended_request()
.
Controls¶
Extensions may wish to define controls for use on existing methods. You will need to define one or more
Control
classes, see Defining Controls for more information about this. The important part for the
purposes of this document is where to place those class definitions in your extension module.
You must define a subclass of LaurelinTransiter
, or the more semantically appropriate but functionally
identical BaseLaurelinControls
. Your subclass must then have local Control
subclasses defined within
it. For example:
from laurelin.ldap import BaseLaurelinExtension, BaseLaurelinControls, Control
class LaurelinExtension(BaseLaurelinExtension):
NAME = 'your_name'
class LaurelinControls(BaseLaurelinControls):
class YourControl(Control):
method = ('search',)
keyword = 'some_kwd'
REQUEST_OID = '1.2.3.4'
Note that controls may alternatively be defined directly in your LaurelinExtension
class.
Schema¶
Extensions may be associated with a set of new schema elements, including object classes, attribute types, matching
rules, and syntax rules. Once defined, these will get used automatically by other parts of laurelin, including the
SchemaValidator
, and for comparing items in attribute value lists within an LDAPObject
.
Like controls, all extension schema elements must be defined as attributes on a subclass of
LaurelinTransiter
. The more semantically appropriate BaseLaurelinSchema
is provided as well. You
can use these base classes to organize your schema and controls however appropriate. Alternatively, you may also define
schema elements directly in your LaurelinExtension
class.
If your schema depends on the laurelin built-in base schema, you must explicitly call
laurelin.ldap.extensions.base_schema.require()
near the top of your extension module.
Below is a simple example of defining a new object class depending on the base schema:
from laurelin.ldap import BaseLaurelinExtension, BaseLaurelinControls, ObjectClass, extensions
extensions.base_schema.require()
class LaurelinExtension(BaseLaurelinExtension):
NAME = 'your_name'
class LaurelinSchema(BaseLaurelinSchema):
MY_COMPANY_USER = ObjectClass('''
( 1.2.3.4 NAME 'myCompanyUser' SUP inetOrgPerson STRUCTURAL
MUST ( companyAttribute $ anotherAttribute )
MAY description
''')
The superclass of inetOrgPerson
makes this example require the base schema. All schema instance elements must be
defined as class attributes in this manner (for object classes and attribute types), and all class elements must be
defined below the LaurelinSchema
class (for syntax rules and matching rules).
Object Classes and Attribute Types¶
Creating object classes and attribute types is very simple. Just take the standard LDAP specification and pass it to the appropriate class constructor. Examples from the netgroups extension:
from laurelin.ldap.objectclass import ObjectClass
from laurelin.ldap.attributetype import AttributeType
ObjectClass('''
( 1.3.6.1.1.1.2.8 NAME 'nisNetgroup' SUP top STRUCTURAL
MUST cn
MAY ( nisNetgroupTriple $ memberNisNetgroup $ description ) )
''')
AttributeType('''
( 1.3.6.1.1.1.1.14 NAME 'nisNetgroupTriple'
DESC 'Netgroup triple'
EQUALITY caseExactMatch
SYNTAX 1.3.6.1.1.1.0.0 )
''')
Matching Rules¶
Defining matching rules takes a little more effort. Matching rules must subclass EqualityMatchingRule
.
Required class attributes include:
OID
- the numeric OID of this rule. Note that this does not need to be IANA-registered to work in laurelin, but it still must be globally unique.NAME
- the name of the rule. Must also be globally unique. This is usually how matching rules are referenced in attribute type specs (seecaseExactMatch
in above example).SYNTAX
- the numeric OID of the syntax rule that assertion values must match.
Matching rule classes may also optionally define the following attribute:
prep_methods
- a sequence of callables that will be used to prepare both the attribute value and assertion value for comparison. These will typically be defined inlaurelin.ldap.rfc4518
. The initial attribute/assertion value will be passed into the first item in the sequence, and the return from each is passed into the next item.
If you prefer, you can also override the MatchingRule.prepare()
method on your matching rule class.
You may also wish to override EqualityMatchingRule.do_match()
. This is passed the two prepared values and must
return a boolean. Overriding MatchingRule.match()
is not recommended.
Below is an example matching rule from laurelin.extensions.base_schema
:
from laurelin.ldap.rules import EqualityMatchingRule
from laurelin.ldap import rfc4518
class numericStringMatch(EqualityMatchingRule):
OID = '2.5.13.8'
NAME = 'numericStringMatch'
SYNTAX = '1.3.6.1.4.1.1466.115.121.1.36'
prep_methods = (
rfc4518.Transcode,
rfc4518.Map.characters,
rfc4518.Normalize,
rfc4518.Prohibit,
rfc4518.Insignificant.numeric_string,
)
Syntax Rules¶
Syntax rules must subclass SyntaxRule
, although in almost all cases you can use RegexSyntaxRule
. If
you do not use a regular expression, you must override SyntaxRule.validate()
, which receives a single string
argument, and must raise InvalidSyntaxError
when it is incorrect.
In all cases, you must define the following attributes on your syntax rule class:
OID
- the numeric OID of the rule. As with matching rules, there is no requirement that this is IANA-registered, but it must be globally unique.DESC
- a brief description of the rule. This is mainly used in exception messages.
Regex syntax rules must also define:
regex
- the regular expression.
Below are examples from laurelin.extensions.base_schema
:
from laurelin.ldap.rules import SyntaxRule, RegexSyntaxRule
from laurelin.ldap.exceptions import InvalidSyntaxError
import six
class DirectoryString(SyntaxRule):
OID = '1.3.6.1.4.1.1466.115.121.1.15'
DESC = 'Directory String'
def validate(self, s):
if not isinstance(s, six.string_types) or (len(s) == 0):
raise InvalidSyntaxError('Not a valid {0}'.format(self.DESC))
class Integer(RegexSyntaxRule):
OID = '1.3.6.1.4.1.1466.115.121.1.27'
DESC = 'INTEGER'
regex = r'^-?[1-9][0-9]*$'
Schema/Controls Registration System¶
Schema and controls go through an identical 2-step registration system. The LaurelinTransiter
class first
stores a list of all schema and control attributes mapped to the module name that defined them. This occurs when the
class is defined, i.e. at import time.
The LaurelinRegistrar.require()
method then invokes the .register()
method on each schema element or control
class defined in the same module. This causes the element to be mapped according to its class, name, and OID - which are
ultimately what is needed for laurelin to make use of the object.
Validators¶
Validators must subclass Validator
. The public interface includes Validator.validate_object()
and
Validator.validate_modify()
. You will usually just want to override these, however they do include a default
implementation which checks all attributes using the abstract Validator._validate_attribute()
. Check method docs
for more information about how to define these.
When defining validators in your extension, you can ensure your users don’t need to import the module again by attaching
the class to your LaurelinExtension
class like so:
from laurelin.ldap import BaseLaurelinExtension, Validator
class LaurelinExtension(BaseLaurelinExtension):
NAME = 'my_ext'
class MyValidator(Validator):
# ...
pass
Users can then access it like so:
from laurelin.ldap import LDAP, extensions
with LDAP('ldaps://dir.example.org', validators=[extensions.my_ext.MyValidator]) as ldap:
# do stuff
SchemaValidator¶
Laurelin ships with SchemaValidator
which, when applied to a connection, automatically checks write operations
for schema validity before sending the request to the server. This includes any schema you define in your extensions.
Users can enable this like so:
from laurelin.ldap import LDAP
from laurelin.ldap.schema import SchemaValidator
with LDAP('ldaps://dir.example.org', validators=[SchemaValidator]) as ldap:
# do stuff
Class Diagram¶
The extension subsystem has several interconnecting classes. Blue are auto-generated classes, and green are defined in extension modules. Unlabeled arrows indicate class inheritance or are self-explanatory.
Controls¶
Many LDAP users may be unfamiliar with controls. RFC4511 defines controls as “providing a mechanism whereby the semantics and arguments of existing LDAP operations may be extended.” In other words, they can:
- Instruct the server to process a method differently
- Add new arguments to methods to control the altered processing
- Add additional data to the response to a method call
It is important to note that both the server and client must mutually support all controls used. Laurelin will automatically check for server support when using controls.
Using Controls¶
Once controls have been defined, they are very easy to use. Each control has a keyword
and optionally a response_attr
.
The keyword
can be passed as a keyword argument to specific methods. The value type and format is up to the control
implementation. Whatever value the control expects can be wrapped in critical
or optional
to declare
the criticality of the control.
If defined, the response_attr
will be set as an attribute on the object returned from the method call.
For search response controls, the control value will be set on the individual LDAPObject
if it appeared on the
associated search result entry. If it appeared on the search results done message, the control value will be set on the
iterator object.
In the highly unusual case that a response control is set on a search result reference message, the control values will
be inaccessible if fetch_result_refs
is set to True. A warning will be issued in this case.
If fetch_result_refs
is set to False, the response control values will be set on the SearchReferenceHandle
that is yielded from the results iterator.
-
class
laurelin.ldap.
optional
(value)[source]¶ Bases:
object
used to mark controls as not having criticality
An LDAPSupportError
will be raised if the control is marked critical and the server does not support it.
Defining Controls¶
Controls must subclass Control. As soon as they are defined as a subclass of Control, they are ready to use. Controls must define at least:
Control.method
, a tuple of method names that this control supports. Current method names are bind, search, compare, add, delete, mod_dn, modify, and ext (extended request). Note that these method names do not necessarily correspond directly toLDAP
method names. Even when they do, other methods may call the base method and pass through control keywords. For example,LDAPObject.find()
ends up passing any control keywords through intoLDAP.search()
(which matches the search method). The bind method is used by bothLDAP.simple_bind()
andLDAP.sasl_bind()
.Control.keyword
, the keyword argument to be used for the request control.Control.REQUEST_OID
the OID of the reuqest control. If the control has criticality, the OID must be listed in the supportedControl attribute of the root DSE of the server at runtime.
If there is an associated response control, also define the following:
Control.response_attr
, the name of the attribute which will be set on objects returned from the method.Control.RESPONSE_OID
the OID of the response control. This may be equal toControl.REQUEST_OID
depending on the spec. This must match the controlType of the response control to be properly set.
Most controls will not need to override methods if only strings are used for request and response values. However, if it
is desirable to use a more complex data structure as a control value, you can override the Control.prepare()
method to accept this structure as its first argument. You will need to process this into a single string for
transmission to the server, and pass it into, and return, the base Control.prepare()
. The second argument is a
boolean describing criticality, and must also be passed into the base method.
To return a more complex value for the response, you can override the Control.handle()
method. This will be
passed the response control value string, and the return will be assigned to the response_attr
attribute on the
returned object.
-
class
laurelin.ldap.controls.
Control
[source]¶ Bases:
object
Request controls are exposed by allowing an additional keyword argument on a set of methods. The prepare() method takes the value passed in as a keyword argument and returns an rfc4511.Control.
Response controls are returned by setting an additional attribute on whichever object is returned by the called method. The raw response controlValue is passed to the handle() method, and any appropriate value may be returned.
Leave the RESPONSE_OID and response_attr attributes as a False value if there is no response control specified.
-
REQUEST_OID
= ''¶ Request OID of the control
-
RESPONSE_OID
= ''¶ Response OID of the control (may be equal to REQUEST_OID; may be left empty)
-
handle
(ctrl_value)[source]¶ Accepts raw response ctrl_value and may return any useful value.
There is no need to call this base function when overriding.
Parameters: ctrl_value (str) – The string response control value received from the server. Returns: The string ctrl_value unchanged by default. May be overridden to return any relevant value/type/structure.
-
keyword
= ''¶ keyword argument name
-
method
= ()¶ name(s) of the method which this control is used with
-
prepare
(ctrl_value, criticality)[source]¶ Accepts string controlValue and returns an rfc4511.Control instance
When overriding this function, you must always call and return this base function.
Parameters: - ctrl_value (str or bytes) – The string request control value to send to the server
- criticality (bool) – True if the control has criticality. This is indicated by wrapping the keyword
argument in
critical
oroptional
, and by the default_criticality keyword passed to theLDAP
constructor, and global defaultLDAP.DEFAULT_CRITICALITY
.
Returns: The protocol-level control object ready for transmission to the server
Return type: rfc4511.Control
-
response_attr
= ''¶ Name of the attribute where return of handle() will be stored
-
Changelog¶
2.0.0¶
Released 2018.11.17
Empty lists in a
replace
ordelete
modify operation are now ignored by default- To delete all attribue values in a replace or delete, use
DELETE_ALL
introduced in version 1.2.0. - To restore the previous functionality, you can set the global default
LDAP.DEFAULT_IGNORE_EMPTY_LIST = False
, or restore on a per-connection basis by passingignore_empty_list=False
to theLDAP()
constructor. - The rationale for this change is a) improved semantics, and b) eliminates unexpected behavior in cases like applying a filter to determine a list to remove (which may result in an empty list, meaning no items should be removed)
- To delete all attribue values in a replace or delete, use
Extensions API has been changed, both for users and creators of extensions:
Rather than attaching new attributes directly to the LDAP or LDAPObject class, a property (or dynamic attribute) is made available on those classes for each extension, which provides access to an object exposing those same attributes.
Many extension attributes have been renamed to avoid semantic duplication introduced by this change. For example
ldap.get_netgroup_users()
should be replaced withldap.netgroups.get_users()
.The base schema will now be automatically loaded when needed. At present, this includes:
- When checking for the presence of a value in an attribute list
- When a
SchemaValidator
is initialized - When the
netgroups
extension is used
The base schema is no longer defined in
laurelin.ldap.schema
. It now is housed in a built-in extension. If previously usingimport laurelin.ldap.schema
or similar to enable client-side schema checking, this should be replaced with something like the following:from laurelin.ldap import extensions extensions.base_schema.require()
However, as stated above, this will not be necessary for almost all use cases.
The
descattrs
extension has been changed slightly to work better with these new changes. Description attributes can now be accessed and modified like so (no additional imports necessary):o = ldap.base.obj('cn=metadata') print(o.descattrs['some_attr']) # ['value1', 'value2'] o.descattrs.add({'some_attr': ['value3']}) print(o.descattrs['some_attr']) # ['value1', 'value2', 'value3'] # these also work now: 'some_attr' in o.descattrs for attr in o.descattrs:
Docs have been updated with information about creating extensions.
Internal changes around loading of schema elements and controls
Properly documented the public API definition
1.5.2¶
Released 2018.06.15
1.5.1 was built off of the wrong branch and will be removed.
- Minor fix: Added FilterSyntax to all
- Doc update: added dependent info section to readme
1.5.0¶
Released 2018.06.09
- Added new simple filter syntax
- Switched default filter syntax to UNIFIED which should be backwards compatible with standard RFC 4515 filters
Special thanks to @jpypi for authoring the new grammar
1.4.1¶
Released 2018.05.31
- Fix: Checked for failed import of AF_UNIX to improve Windows support
- Fix: Required latest pure-sasl
1.4.0¶
Released 2018.05.29
Validation updates:
- Added
LDAP.disable_validation()
which creates a context with any or all validators skipped - Added an
ldap_conn
attribute to validator instances to allow validators to query the server - Allowed passing a class as well as an instance with the
validators
constructor keyword
- Added
Greatly improved handling of unsolcitied messages (message ID 0)
Fix: enforce maximum length for attribute types
Fix: SASL auth issues with pure-sasl 0.5.1+
1.3.1¶
Released 2018.04.01
- Fixed logic bug in
SchemaValidator
when an object has two or more object classes that require one or more of the same attributes - Fixed: allowed string
some.module.Class
specification for validators in config files
1.3.0¶
Released 2018.03.22
- Added config file support, see
laurelin.ldap.config
- Fixed: ensured extensions can be safely activated multiple times
- Fixed:
Mod
constantsrepr
updated for consistency
1.2.0¶
Released 2018.03.16
- Add DELETE_ALL to use as an attribute value list with modify, replace_attrs, and delete_attrs
- Added new constructor keywords to alter the behavior of empty value lists for modify, replace_attrs, and delete_attrs:
ignore_empty_list
to silently ignore empty value lists and not send them to the server. This will be enabled by default in a future release.error_empty_list
to raise an exception when an empty value list is passed.warn_empty_list
to emit a warning when an empty value list is passed.
Reference¶
laurelin package¶
Subpackages¶
laurelin.extensions package¶
Submodules¶
-
class
laurelin.extensions.base_schema.
LaurelinExtension
(modname=None)[source]¶ Bases:
laurelin.ldap.extensible.user_base.BaseLaurelinExtension
-
NAME
= 'base_schema'¶
-
-
class
laurelin.extensions.base_schema.
LaurelinSchema
[source]¶ Bases:
laurelin.ldap.extensible.user_base.BaseLaurelinSchema
-
ACCOUNT
= <ObjectClass "account">¶
-
ALIAS
= <ObjectClass "alias">¶
-
ALIASED_OBJECT_NAME
= <AttributeType "aliasedObjectName">¶
-
ALT_SERVER
= <AttributeType "altServer">¶
-
APPLICATION_PROCESS
= <ObjectClass "applicationProcess">¶
-
ASSOCIATED_DOMAIN
= <AttributeType "associatedDomain">¶
-
ASSOCIATED_NAME
= <AttributeType "associatedName">¶
-
ATTRIBUTE_TYPES
= <AttributeType "attributeTypes">¶
-
AUDIO
= <AttributeType "audio">¶
-
class
AttributeTypeDescription
[source]¶ Bases:
laurelin.ldap.rules.RegexSyntaxRule
-
DESC
= 'Attribute Type Description'¶
-
OID
= '1.3.6.1.4.1.1466.115.121.1.3'¶
-
regex
= "^\\( *(?P<oid>[0-9]+(?:\\.[0-9]+)+)(?: +NAME +(?P<name>(?:'[A-Za-z][A-Za-z0-9-]*'|\\( *'[A-Za-z][A-Za-z0-9-]*'(?: +'[A-Za-z][A-Za-z0-9-]*')* *\\))))?(?: +DESC +(?P<desc>'(?:\\\\5[Cc]|\\\\27|[^'\\\\])+'))?(?P<obsolete> +OBSOLETE)?(?: +SUP +(?P<supertype>(?:[A-Za-z][A-Za-z0-9-]*|[0-9]+(?:\\.[0-9]+)+)))?(?: +EQUALITY +(?P<equality>(?:[A-Za-z][A-Za-z0-9-]*|[0-9]+(?:\\.[0-9]+)+)))?(?: +ORDERING +(?P<ordering>(?:[A-Za-z][A-Za-z0-9-]*|[0-9]+(?:\\.[0-9]+)+)))?(?: +SUBSTR +(?P<substr>(?:[A-Za-z][A-Za-z0-9-]*|[0-9]+(?:\\.[0-9]+)+)))?(?: +SYNTAX +(?P<syntax>[0-9]+(?:\\.[0-9]+)+(\\{[0-9]+\\})?))?(?P<single_value> +SINGLE-VALUE)?(?P<collective> +COLLECTIVE)?(?P<no_user_mod> +NO-USER-MODIFICATION)?(?: +USAGE +(?P<usage>userApplications|directoryOperation|distributedOperation|dSAOperation))?(?P<extensions> (?:X-[A-Za-z_-]+) (?:'(?:\\\\5[Cc]|\\\\27|[^'\\\\])+'|\\( *'(?:\\\\5[Cc]|\\\\27|[^'\\\\])+'(?: +'(?:\\\\5[Cc]|\\\\27|[^'\\\\])+')* *\\)))? *\\)$"¶
-
-
BUILDING_NAME
= <AttributeType "buildingName">¶
-
BUSINESS_CATEGORY
= <AttributeType "businessCategory">¶
-
class
Binary
[source]¶ Bases:
laurelin.ldap.rules.SyntaxRule
-
DESC
= 'Binary'¶
-
OID
= '1.3.6.1.4.1.1466.115.121.1.5'¶
-
validate
(s)[source]¶ Validate a string. Must be implemented by subclasses.
Parameters: s – Candidate string Returns: Any useful value for the rule Raises: InvalidSyntaxError – if the string is invalid
-
-
class
BitString
[source]¶ Bases:
laurelin.ldap.rules.RegexSyntaxRule
-
DESC
= 'Bit String'¶
-
OID
= '1.3.6.1.4.1.1466.115.121.1.6'¶
-
regex
= "^'[01]*'B$"¶
-
-
class
BitStringMatch
[source]¶ Bases:
laurelin.ldap.rules.EqualityMatchingRule
-
NAME
= 'bitStringMatch'¶
-
OID
= '2.5.13.16'¶
-
SYNTAX
= '1.3.6.1.4.1.1466.115.121.1.6'¶
-
-
class
Boolean
[source]¶ Bases:
laurelin.ldap.rules.SyntaxRule
-
DESC
= 'Boolean'¶
-
OID
= '1.3.6.1.4.1.1466.115.121.1.7'¶
-
validate
(s)[source]¶ Validate a string. Must be implemented by subclasses.
Parameters: s – Candidate string Returns: Any useful value for the rule Raises: InvalidSyntaxError – if the string is invalid
-
-
class
BooleanMatch
[source]¶ Bases:
laurelin.ldap.rules.EqualityMatchingRule
-
NAME
= 'booleanMatch'¶
-
OID
= '2.5.13.13'¶
-
SYNTAX
= '1.3.6.1.4.1.1466.115.121.1.7'¶
-
-
C
= <AttributeType "c">¶
-
CAR_LICENSE
= <AttributeType "carLicense">¶
-
CN
= <AttributeType "cn">¶
-
CO
= <AttributeType "co">¶
-
COUNTRY
= <ObjectClass "country">¶
-
CREATE_TIMESTAMP
= <AttributeType "createTimestamp">¶
-
CREATORS_NAME
= <AttributeType "creatorsName">¶
-
class
CaseExactIA5Match
[source]¶ Bases:
laurelin.ldap.rules.EqualityMatchingRule
-
NAME
= 'caseExactIA5Match'¶
-
OID
= '1.3.6.1.4.1.1466.109.114.1'¶
-
SYNTAX
= '1.3.6.1.4.1.1466.115.121.1.26'¶
-
prep_methods
= (<function Transcode>, <function Map.characters>, <function Normalize>, <function Prohibit>, <function Insignificant.space>)¶
-
-
class
CaseExactMatch
[source]¶ Bases:
laurelin.ldap.rules.EqualityMatchingRule
-
NAME
= 'caseExactMatch'¶
-
OID
= '2.5.13.5'¶
-
SYNTAX
= '1.3.6.1.4.1.1466.115.121.1.15'¶
-
prep_methods
= (<function Transcode>, <function Map.characters>, <function Normalize>, <function Prohibit>, <function Insignificant.space>)¶
-
-
class
CaseIgnoreIA5Match
[source]¶ Bases:
laurelin.ldap.rules.EqualityMatchingRule
-
NAME
= 'caseIgnoreIA5Match'¶
-
OID
= '1.3.6.1.4.1.1466.109.114.2'¶
-
SYNTAX
= '1.3.6.1.4.1.1466.115.121.1.26'¶
-
prep_methods
= (<function Transcode>, <function Map.all>, <function Normalize>, <function Prohibit>, <function Insignificant.space>)¶
-
-
class
CaseIgnoreListMatch
[source]¶ Bases:
laurelin.ldap.rules.EqualityMatchingRule
-
NAME
= 'caseIgnoreListMatch'¶
-
OID
= '2.5.13.11'¶
-
SYNTAX
= '1.3.6.1.4.1.1466.115.121.1.41'¶
-
prep_methods
= (<function Transcode>, <function Map.all>, <function Normalize>, <function Prohibit>, <function Insignificant.space>)¶
-
-
class
CaseIgnoreMatch
[source]¶ Bases:
laurelin.ldap.rules.EqualityMatchingRule
-
NAME
= 'caseIgnoreMatch'¶
-
OID
= '2.5.13.2'¶
-
SYNTAX
= '1.3.6.1.4.1.1466.115.121.1.15'¶
-
prep_methods
= (<function Transcode>, <function Map.all>, <function Normalize>, <function Prohibit>, <function Insignificant.space>)¶
-
-
class
Certificate
[source]¶ Bases:
laurelin.ldap.rules.SyntaxRule
-
DESC
= 'Certificate'¶
-
OID
= '1.3.6.1.4.1.1466.115.121.1.8'¶
-
validate
(s)[source]¶ Validate a string. Must be implemented by subclasses.
Parameters: s – Candidate string Returns: Any useful value for the rule Raises: InvalidSyntaxError – if the string is invalid
-
-
class
CountryString
[source]¶ Bases:
laurelin.ldap.rules.RegexSyntaxRule
-
DESC
= 'Country String'¶
-
OID
= '1.3.6.1.4.1.1466.115.121.1.11'¶
-
regex
= "^[A-Za-z0-9'()+,.=/:? -]{2}$"¶
-
-
DC
= <AttributeType "dc">¶
-
DC_OBJECT
= <ObjectClass "dcObject">¶
-
DEPARTMENT_NUMBER
= <AttributeType "departmentNumber">¶
-
DESCRIPTION
= <AttributeType "description">¶
-
DESTINATION_INDICATOR
= <AttributeType "destinationIndicator">¶
-
DEVICE
= <ObjectClass "device">¶
-
DISPLAY_NAME
= <AttributeType "displayName">¶
-
DISTINGUISHED_NAME
= <AttributeType "distinguishedName">¶
-
class
DITContentRuleDescription
[source]¶ Bases:
laurelin.ldap.rules.RegexSyntaxRule
-
DESC
= 'DIT Content Rule Description'¶
-
OID
= '1.3.6.1.4.1.1466.115.121.1.16'¶
-
regex
= "^\\( *(?P<oid>[0-9]+(?:\\.[0-9]+)+)(?: +NAME +(?:'[A-Za-z][A-Za-z0-9-]*'|\\( *'[A-Za-z][A-Za-z0-9-]*'(?: +'[A-Za-z][A-Za-z0-9-]*')* *\\)))?(?: +DESC +'(?:\\\\5[Cc]|\\\\27|[^'\\\\])+')?(?: +OBSOLETE +)?(?: +AUX +(?:(?:[A-Za-z][A-Za-z0-9-]*|[0-9]+(?:\\.[0-9]+)+)|\\( *(?:[A-Za-z][A-Za-z0-9-]*|[0-9]+(?:\\.[0-9]+)+)(?: *\\$ *(?:[A-Za-z][A-Za-z0-9-]*|[0-9]+(?:\\.[0-9]+)+))* *\\)))?(?: +MUST +(?:(?:[A-Za-z][A-Za-z0-9-]*|[0-9]+(?:\\.[0-9]+)+)|\\( *(?:[A-Za-z][A-Za-z0-9-]*|[0-9]+(?:\\.[0-9]+)+)(?: *\\$ *(?:[A-Za-z][A-Za-z0-9-]*|[0-9]+(?:\\.[0-9]+)+))* *\\)))?(?: +NOT +(?:(?:[A-Za-z][A-Za-z0-9-]*|[0-9]+(?:\\.[0-9]+)+)|\\( *(?:[A-Za-z][A-Za-z0-9-]*|[0-9]+(?:\\.[0-9]+)+)(?: *\\$ *(?:[A-Za-z][A-Za-z0-9-]*|[0-9]+(?:\\.[0-9]+)+))* *\\)))?(?P<extensions> (?:X-[A-Za-z_-]+) (?:'(?:\\\\5[Cc]|\\\\27|[^'\\\\])+'|\\( *'(?:\\\\5[Cc]|\\\\27|[^'\\\\])+'(?: +'(?:\\\\5[Cc]|\\\\27|[^'\\\\])+')* *\\)))? *\\)$"¶
-
-
class
DITStructureRuleDescription
[source]¶ Bases:
laurelin.ldap.rules.RegexSyntaxRule
-
DESC
= 'DIT Structure Rule Description'¶
-
OID
= '1.3.6.1.4.1.1466.115.121.1.17'¶
-
regex
= "^\\( *(?:[0-9]+)(?: +NAME +(?:'[A-Za-z][A-Za-z0-9-]*'|\\( *'[A-Za-z][A-Za-z0-9-]*'(?: +'[A-Za-z][A-Za-z0-9-]*')* *\\)))?(?: +DESC +'(?:\\\\5[Cc]|\\\\27|[^'\\\\])+')?(?: +OBSOLETE +)?(?: +FORM +(?:[A-Za-z][A-Za-z0-9-]*|[0-9]+(?:\\.[0-9]+)+))(?: +SUP +(?:[0-9]+|\\( *[0-9]+(?: +[0-9]+)* *\\)))?(?P<extensions> (?:X-[A-Za-z_-]+) (?:'(?:\\\\5[Cc]|\\\\27|[^'\\\\])+'|\\( *'(?:\\\\5[Cc]|\\\\27|[^'\\\\])+'(?: +'(?:\\\\5[Cc]|\\\\27|[^'\\\\])+')* *\\)))? *\\)$"¶
-
-
DIT_CONTENT_RULES
= <AttributeType "dITContentRules">¶
-
DIT_STRUCTURE_RULES
= <AttributeType "dITStructureRules">¶
-
DN_QUALIFIER
= <AttributeType "dnQualifier">¶
-
DOCUMENT
= <ObjectClass "document">¶
-
DOCUMENT_AUTHOR
= <AttributeType "documentAuthor">¶
-
DOCUMENT_IDENTIFIER
= <AttributeType "documentIdentifier">¶
-
DOCUMENT_LOCATION
= <AttributeType "documentLocation">¶
-
DOCUMENT_PUBLISHER
= <AttributeType "documentPublisher">¶
-
DOCUMENT_SERIES
= <ObjectClass "documentSeries">¶
-
DOCUMENT_TITLE
= <AttributeType "documentTitle">¶
-
DOCUMENT_VERSION
= <AttributeType "documentVersion">¶
-
DOMAIN
= <ObjectClass "domain">¶
-
DOMAIN_RELATED_OBJECT
= <ObjectClass "domainRelatedObject">¶
-
DRINK
= <AttributeType "drink">¶
-
class
DeliveryMethod
[source]¶ Bases:
laurelin.ldap.rules.RegexSyntaxRule
-
DESC
= 'Delivery Method'¶
-
OID
= '1.3.6.1.4.1.1466.115.121.1.14'¶
-
regex
= '^(?:any|mhs|physical|telex|teletext|g3fax|g4fax|ia5|videotext|telephone)(\\s*\\$\\s*(?:any|mhs|physical|telex|teletext|g3fax|g4fax|ia5|videotext|telephone))*$'¶
-
-
class
DirectoryString
[source]¶ Bases:
laurelin.ldap.rules.SyntaxRule
-
DESC
= 'Directory String'¶
-
OID
= '1.3.6.1.4.1.1466.115.121.1.15'¶
-
validate
(s)[source]¶ Validate a string. Must be implemented by subclasses.
Parameters: s – Candidate string Returns: Any useful value for the rule Raises: InvalidSyntaxError – if the string is invalid
-
-
class
DirectoryStringFirstComponentMatch
[source]¶ Bases:
laurelin.ldap.rules.EqualityMatchingRule
-
NAME
= 'directoryStringFirstComponentMatch'¶
-
OID
= '2.5.13.31'¶
-
SYNTAX
= '1.3.6.1.4.1.1466.115.121.1.15'¶
-
-
class
DistinguishedName
[source]¶ Bases:
laurelin.ldap.rules.RegexSyntaxRule
-
DESC
= 'DN'¶
-
OID
= '1.3.6.1.4.1.1466.115.121.1.12'¶
-
regex
= '^(?:[A-Za-z][A-Za-z0-9-]*|[0-9]+(?:\\.[0-9]+)+)=(?:(?:[^"+,;<>\\0\\\\ #=]|\\\\(["+,;<>\\0\\\\ #=]|[0-9A-Fa-f]{2}))(?:[^"+,;<>\\0\\\\]|\\\\(["+,;<>\\0\\\\ #=]|[0-9A-Fa-f]{2}))*(?:[^"+,;<>\\0\\\\ ]|\\\\(["+,;<>\\0\\\\ #=]|[0-9A-Fa-f]{2}))?|#(?:[0-9A-Fa-f]{2})+)(?:\\+(?:[A-Za-z][A-Za-z0-9-]*|[0-9]+(?:\\.[0-9]+)+)=(?:(?:[^"+,;<>\\0\\\\ #=]|\\\\(["+,;<>\\0\\\\ #=]|[0-9A-Fa-f]{2}))(?:[^"+,;<>\\0\\\\]|\\\\(["+,;<>\\0\\\\ #=]|[0-9A-Fa-f]{2}))*(?:[^"+,;<>\\0\\\\ ]|\\\\(["+,;<>\\0\\\\ #=]|[0-9A-Fa-f]{2}))?|#(?:[0-9A-Fa-f]{2})+))*(?:,(?:[A-Za-z][A-Za-z0-9-]*|[0-9]+(?:\\.[0-9]+)+)=(?:(?:[^"+,;<>\\0\\\\ #=]|\\\\(["+,;<>\\0\\\\ #=]|[0-9A-Fa-f]{2}))(?:[^"+,;<>\\0\\\\]|\\\\(["+,;<>\\0\\\\ #=]|[0-9A-Fa-f]{2}))*(?:[^"+,;<>\\0\\\\ ]|\\\\(["+,;<>\\0\\\\ #=]|[0-9A-Fa-f]{2}))?|#(?:[0-9A-Fa-f]{2})+)(?:\\+(?:[A-Za-z][A-Za-z0-9-]*|[0-9]+(?:\\.[0-9]+)+)=(?:(?:[^"+,;<>\\0\\\\ #=]|\\\\(["+,;<>\\0\\\\ #=]|[0-9A-Fa-f]{2}))(?:[^"+,;<>\\0\\\\]|\\\\(["+,;<>\\0\\\\ #=]|[0-9A-Fa-f]{2}))*(?:[^"+,;<>\\0\\\\ ]|\\\\(["+,;<>\\0\\\\ #=]|[0-9A-Fa-f]{2}))?|#(?:[0-9A-Fa-f]{2})+))*)*$'¶
-
-
class
DistinguishedNameMatch
[source]¶ Bases:
laurelin.ldap.rules.EqualityMatchingRule
-
NAME
= 'distinguishedNameMatch'¶
-
OID
= '2.5.13.1'¶
-
SYNTAX
= '1.3.6.1.4.1.1466.115.121.1.12'¶
-
-
EMPLOYEE_NUMBER
= <AttributeType "employeeNumber">¶
-
EMPLOYEE_TYPE
= <AttributeType "employeeType">¶
-
ENHANCED_SEARCH_GUIDE
= <AttributeType "enhancedSearchGuide">¶
-
EXTENSIBLE_OBJECT
= <ExtensibleObjectClass "extensibleObject">¶
-
class
EnhancedGuide
[source]¶ Bases:
laurelin.ldap.rules.SyntaxRule
-
DESC
= 'Enhanced Guide'¶
-
OID
= '1.3.6.1.4.1.1466.115.121.1.21'¶
-
validate
(s)[source]¶ Validate a string. Must be implemented by subclasses.
Parameters: s – Candidate string Returns: Any useful value for the rule Raises: InvalidSyntaxError – if the string is invalid
-
-
FACSIMILIE_TELEPHONE_NUMBER
= <AttributeType "facsimileTelephoneNumber">¶
-
FRIENDLY_COUNTRY
= <ObjectClass "friendlyCountry">¶
-
class
FacsimilieTelephoneNumber
[source]¶ Bases:
laurelin.ldap.rules.SyntaxRule
-
DESC
= 'Facsimile Telephone Number'¶
-
OID
= '1.3.6.1.4.1.1466.115.121.1.22'¶
-
validate
(s)[source]¶ Validate a string. Must be implemented by subclasses.
Parameters: s – Candidate string Returns: Any useful value for the rule Raises: InvalidSyntaxError – if the string is invalid
-
-
class
Fax
[source]¶ Bases:
laurelin.ldap.rules.SyntaxRule
-
DESC
= 'Fax'¶
-
OID
= '1.3.6.1.4.1.1466.115.121.1.23'¶
-
validate
(s)[source]¶ Validate a string. Must be implemented by subclasses.
Parameters: s – Candidate string Returns: Any useful value for the rule Raises: InvalidSyntaxError – if the string is invalid
-
-
GENERATION_QUALIFIER
= <AttributeType "generationQualifier">¶
-
GIVEN_NAME
= <AttributeType "givenName">¶
-
GOVERNING_STRUCTURAL_RULE
= <AttributeType "governingStructureRule">¶
-
GROUP_OF_NAMES
= <ObjectClass "groupOfNames">¶
-
GROUP_OF_UNIQUE_NAMES
= <ObjectClass "groupOfUniqueNames">¶
-
class
GeneralizedTime
[source]¶ Bases:
laurelin.ldap.rules.RegexSyntaxRule
-
DESC
= 'Generalized Time'¶
-
OID
= '1.3.6.1.4.1.1466.115.121.1.24'¶
-
regex
= '^([0-9]{4})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})?([0-9]{2})?([.,][0-9]+)?(Z|[+-]([0-9]{2})([0-9]{2})?)$'¶
-
validate
(s)[source]¶ Validate a string against the regular expression.
Parameters: s – Candidate string Returns: The regex match object Return type: MatchObject Raises: InvalidSyntaxError – if the string does not match
-
-
class
GeneralizedTimeMatch
[source]¶ Bases:
laurelin.ldap.rules.EqualityMatchingRule
-
NAME
= 'generalizedTimeMatch'¶
-
OID
= '2.5.13.27'¶
-
SYNTAX
= '1.3.6.1.4.1.1466.115.121.1.24'¶
-
-
class
Guide
[source]¶ Bases:
laurelin.extensions.base_schema.EnhancedGuide
-
DESC
= 'Guide'¶
-
OID
= '1.3.6.1.4.1.1466.115.121.1.25'¶
-
validate
(s)[source]¶ Validate a string. Must be implemented by subclasses.
Parameters: s – Candidate string Returns: Any useful value for the rule Raises: InvalidSyntaxError – if the string is invalid
-
-
HOME_PHONE
= <AttributeType "homePhone">¶
-
HOME_POSTAL_ADDRESS
= <AttributeType "homePostalAddress">¶
-
HOST
= <AttributeType "host">¶
-
HOUSE_IDENTIFIER
= <AttributeType "houseIdentifier">¶
-
class
IA5String
[source]¶ Bases:
laurelin.ldap.rules.RegexSyntaxRule
-
DESC
= 'IA5 String'¶
-
OID
= '1.3.6.1.4.1.1466.115.121.1.26'¶
-
regex
= '^[\\x00-\\x7f]*$'¶
-
-
INET_ORG_PERSON
= <ObjectClass "inetOrgPerson">¶
-
INFO
= <AttributeType "info">¶
-
INITIALS
= <AttributeType "initials">¶
-
INTERNATIONAL_ISDN_NUMBER
= <AttributeType "internationalISDNNumber">¶
-
class
Integer
[source]¶ Bases:
laurelin.ldap.rules.RegexSyntaxRule
-
DESC
= 'INTEGER'¶
-
OID
= '1.3.6.1.4.1.1466.115.121.1.27'¶
-
regex
= '^-?[1-9][0-9]*$'¶
-
-
class
IntegerFirstComponentMatch
[source]¶ Bases:
laurelin.ldap.rules.EqualityMatchingRule
-
NAME
= 'integerFirstComponentMatch'¶
-
OID
= '2.5.13.29'¶
-
SYNTAX
= '1.3.6.1.4.1.1466.115.121.1.27'¶
-
-
class
IntegerMatch
[source]¶ Bases:
laurelin.ldap.rules.EqualityMatchingRule
-
NAME
= 'integerMatch'¶
-
OID
= '2.5.13.14'¶
-
SYNTAX
= '1.3.6.1.4.1.1466.115.121.1.27'¶
-
-
class
JPEG
[source]¶ Bases:
laurelin.ldap.rules.SyntaxRule
-
DESC
= 'JPEG'¶
-
OID
= '1.3.6.1.4.1.1466.115.121.1.28'¶
-
validate
(s)[source]¶ Validate a string. Must be implemented by subclasses.
Parameters: s – Candidate string Returns: Any useful value for the rule Raises: InvalidSyntaxError – if the string is invalid
-
-
JPEG_PHOTO
= <AttributeType "jpegPhoto">¶
-
L
= <AttributeType "l">¶
-
LABELED_URI
= <AttributeType "labeledURI">¶
-
class
LDAPSyntaxDescription
[source]¶ Bases:
laurelin.ldap.rules.RegexSyntaxRule
-
DESC
= 'LDAP Syntax Description'¶
-
OID
= '1.3.6.1.4.1.1466.115.121.1.54'¶
-
regex
= "^\\( *(?P<oid>[0-9]+(?:\\.[0-9]+)+)(?: +DESC +'(?:\\\\5[Cc]|\\\\27|[^'\\\\])+')?(?P<extensions> (?:X-[A-Za-z_-]+) (?:'(?:\\\\5[Cc]|\\\\27|[^'\\\\])+'|\\( *'(?:\\\\5[Cc]|\\\\27|[^'\\\\])+'(?: +'(?:\\\\5[Cc]|\\\\27|[^'\\\\])+')* *\\)))? *\\)$"¶
-
-
LDAP_SYNTAXES
= <AttributeType "ldapSyntaxes">¶
-
LOCALITY
= <ObjectClass "locality">¶
-
MAIL
= <AttributeType "mail">¶
-
MANAGER
= <AttributeType "manager">¶
-
MATCHING_RULES
= <AttributeType "matchingRules">¶
-
MATCHING_RULES_USE
= <AttributeType "matchingRuleUse">¶
-
MEMBER
= <AttributeType "member">¶
-
MOBILE
= <AttributeType "mobile">¶
-
MODIFIERS_NAME
= <AttributeType "modifiersName">¶
-
MODIFY_TIMESTAMP
= <AttributeType "modifyTimestamp">¶
-
class
MatchingRuleDescription
[source]¶ Bases:
laurelin.ldap.rules.RegexSyntaxRule
-
DESC
= 'Matching Rule Description'¶
-
OID
= '1.3.6.1.4.1.1466.115.121.1.30'¶
-
regex
= "^\\( *(?P<oid>[0-9]+(?:\\.[0-9]+)+)(?: +NAME +(?:'[A-Za-z][A-Za-z0-9-]*'|\\( *'[A-Za-z][A-Za-z0-9-]*'(?: +'[A-Za-z][A-Za-z0-9-]*')* *\\)))?(?: +DESC +'(?:\\\\5[Cc]|\\\\27|[^'\\\\])+')?(?: +OBSOLETE)?(?: +SYNTAX +(?:(?:[A-Za-z][A-Za-z0-9-]*|[0-9]+(?:\\.[0-9]+)+)|\\( *(?:[A-Za-z][A-Za-z0-9-]*|[0-9]+(?:\\.[0-9]+)+)(?: *\\$ *(?:[A-Za-z][A-Za-z0-9-]*|[0-9]+(?:\\.[0-9]+)+))* *\\)))(?P<extensions> (?:X-[A-Za-z_-]+) (?:'(?:\\\\5[Cc]|\\\\27|[^'\\\\])+'|\\( *'(?:\\\\5[Cc]|\\\\27|[^'\\\\])+'(?: +'(?:\\\\5[Cc]|\\\\27|[^'\\\\])+')* *\\)))? *\\)$"¶
-
-
class
MatchingRuleUseDescription
[source]¶ Bases:
laurelin.ldap.rules.RegexSyntaxRule
-
DESC
= 'Matching Rule Use Description'¶
-
OID
= '1.3.6.1.4.1.1466.115.121.1.31'¶
-
regex
= "^\\( *(?P<oid>[0-9]+(?:\\.[0-9]+)+)(?: +NAME +(?:'[A-Za-z][A-Za-z0-9-]*'|\\( *'[A-Za-z][A-Za-z0-9-]*'(?: +'[A-Za-z][A-Za-z0-9-]*')* *\\)))?(?: +DESC +'(?:\\\\5[Cc]|\\\\27|[^'\\\\])+')?(?: +OBSOLETE)?(?: +APPLIES +(?:(?:[A-Za-z][A-Za-z0-9-]*|[0-9]+(?:\\.[0-9]+)+)|\\( *(?:[A-Za-z][A-Za-z0-9-]*|[0-9]+(?:\\.[0-9]+)+)(?: *\\$ *(?:[A-Za-z][A-Za-z0-9-]*|[0-9]+(?:\\.[0-9]+)+))* *\\)))(?P<extensions> (?:X-[A-Za-z_-]+) (?:'(?:\\\\5[Cc]|\\\\27|[^'\\\\])+'|\\( *'(?:\\\\5[Cc]|\\\\27|[^'\\\\])+'(?: +'(?:\\\\5[Cc]|\\\\27|[^'\\\\])+')* *\\)))? *\\)$"¶
-
-
NAME
= <AttributeType "name">¶
-
NAME_FORMS
= <AttributeType "nameForms">¶
-
NAMING_CONTEXTS
= <AttributeType "namingContexts">¶
-
class
NameAndOptionalUID
[source]¶ Bases:
laurelin.ldap.rules.RegexSyntaxRule
-
DESC
= 'Name And Optional UID'¶
-
OID
= '1.3.6.1.4.1.1466.115.121.1.34'¶
-
regex
= '^(?:[A-Za-z][A-Za-z0-9-]*|[0-9]+(?:\\.[0-9]+)+)=(?:(?:[^"+,;<>\\0\\\\ #=]|\\\\(["+,;<>\\0\\\\ #=]|[0-9A-Fa-f]{2}))(?:[^"+,;<>\\0\\\\]|\\\\(["+,;<>\\0\\\\ #=]|[0-9A-Fa-f]{2}))*(?:[^"+,;<>\\0\\\\ ]|\\\\(["+,;<>\\0\\\\ #=]|[0-9A-Fa-f]{2}))?|#(?:[0-9A-Fa-f]{2})+)(?:\\+(?:[A-Za-z][A-Za-z0-9-]*|[0-9]+(?:\\.[0-9]+)+)=(?:(?:[^"+,;<>\\0\\\\ #=]|\\\\(["+,;<>\\0\\\\ #=]|[0-9A-Fa-f]{2}))(?:[^"+,;<>\\0\\\\]|\\\\(["+,;<>\\0\\\\ #=]|[0-9A-Fa-f]{2}))*(?:[^"+,;<>\\0\\\\ ]|\\\\(["+,;<>\\0\\\\ #=]|[0-9A-Fa-f]{2}))?|#(?:[0-9A-Fa-f]{2})+))*(?:,(?:[A-Za-z][A-Za-z0-9-]*|[0-9]+(?:\\.[0-9]+)+)=(?:(?:[^"+,;<>\\0\\\\ #=]|\\\\(["+,;<>\\0\\\\ #=]|[0-9A-Fa-f]{2}))(?:[^"+,;<>\\0\\\\]|\\\\(["+,;<>\\0\\\\ #=]|[0-9A-Fa-f]{2}))*(?:[^"+,;<>\\0\\\\ ]|\\\\(["+,;<>\\0\\\\ #=]|[0-9A-Fa-f]{2}))?|#(?:[0-9A-Fa-f]{2})+)(?:\\+(?:[A-Za-z][A-Za-z0-9-]*|[0-9]+(?:\\.[0-9]+)+)=(?:(?:[^"+,;<>\\0\\\\ #=]|\\\\(["+,;<>\\0\\\\ #=]|[0-9A-Fa-f]{2}))(?:[^"+,;<>\\0\\\\]|\\\\(["+,;<>\\0\\\\ #=]|[0-9A-Fa-f]{2}))*(?:[^"+,;<>\\0\\\\ ]|\\\\(["+,;<>\\0\\\\ #=]|[0-9A-Fa-f]{2}))?|#(?:[0-9A-Fa-f]{2})+))*)*(?:#\'[01]*\'B)?'¶
-
-
class
NameFormDescription
[source]¶ Bases:
laurelin.ldap.rules.RegexSyntaxRule
-
DESC
= 'Name Form Description'¶
-
OID
= '1.3.6.1.4.1.1466.115.121.1.35'¶
-
regex
= "^\\( *(?:[0-9]+(?:\\.[0-9]+)+)(?: +NAME +(?:'[A-Za-z][A-Za-z0-9-]*'|\\( *'[A-Za-z][A-Za-z0-9-]*'(?: +'[A-Za-z][A-Za-z0-9-]*')* *\\)))?(?: +DESC +'(?:\\\\5[Cc]|\\\\27|[^'\\\\])+')?(?: +OBSOLETE)?(?: +OC +(?:[A-Za-z][A-Za-z0-9-]*|[0-9]+(?:\\.[0-9]+)+))(?: +MUST +(?:(?:[A-Za-z][A-Za-z0-9-]*|[0-9]+(?:\\.[0-9]+)+)|\\( *(?:[A-Za-z][A-Za-z0-9-]*|[0-9]+(?:\\.[0-9]+)+)(?: *\\$ *(?:[A-Za-z][A-Za-z0-9-]*|[0-9]+(?:\\.[0-9]+)+))* *\\)))(?: +MAY +(?:(?:[A-Za-z][A-Za-z0-9-]*|[0-9]+(?:\\.[0-9]+)+)|\\( *(?:[A-Za-z][A-Za-z0-9-]*|[0-9]+(?:\\.[0-9]+)+)(?: *\\$ *(?:[A-Za-z][A-Za-z0-9-]*|[0-9]+(?:\\.[0-9]+)+))* *\\)))?(?P<extensions> (?:X-[A-Za-z_-]+) (?:'(?:\\\\5[Cc]|\\\\27|[^'\\\\])+'|\\( *'(?:\\\\5[Cc]|\\\\27|[^'\\\\])+'(?: +'(?:\\\\5[Cc]|\\\\27|[^'\\\\])+')* *\\)))? *\\)$"¶
-
-
class
NumericString
[source]¶ Bases:
laurelin.ldap.rules.RegexSyntaxRule
-
DESC
= 'Numeric String'¶
-
OID
= '1.3.6.1.4.1.1466.115.121.1.36'¶
-
regex
= '^[0-9 ]+$'¶
-
-
class
NumericStringMatch
[source]¶ Bases:
laurelin.ldap.rules.EqualityMatchingRule
-
NAME
= 'numericStringMatch'¶
-
OID
= '2.5.13.8'¶
-
SYNTAX
= '1.3.6.1.4.1.1466.115.121.1.36'¶
-
prep_methods
= (<function Transcode>, <function Map.characters>, <function Normalize>, <function Prohibit>, <function Insignificant.numeric_string>)¶
-
-
O
= <AttributeType "o">¶
-
OBJECT_CLASS
= <AttributeType "objectClass">¶
-
OBJECT_CLASSES
= <AttributeType "objectClasses">¶
-
class
OID
[source]¶ Bases:
laurelin.ldap.rules.RegexSyntaxRule
-
DESC
= 'OID'¶
-
OID
= '1.3.6.1.4.1.1466.115.121.1.38'¶
-
regex
= '^(?:[A-Za-z][A-Za-z0-9-]*|[0-9]+(?:\\.[0-9]+)+)$'¶
-
-
ORGANIZATION
= <ObjectClass "organization">¶
-
ORGANIZATIONAL_PERSON
= <ObjectClass "organizationalPerson">¶
-
ORGANIZATIONAL_ROLE
= <ObjectClass "organizationalRole">¶
-
ORGANIZATIONAL_STATUS
= <AttributeType "organizationalStatus">¶
-
ORGANIZATIONAL_UNIT
= <ObjectClass "organizationalUnit">¶
-
OU
= <AttributeType "ou">¶
-
OWNER
= <AttributeType "owner">¶
-
class
ObjectClassDescription
[source]¶ Bases:
laurelin.ldap.rules.RegexSyntaxRule
-
DESC
= 'Object Class Description'¶
-
OID
= '1.3.6.1.4.1.1466.115.121.1.37'¶
-
regex
= "^\\( *(?P<oid>[0-9]+(?:\\.[0-9]+)+)(?: +NAME +(?P<name>(?:'[A-Za-z][A-Za-z0-9-]*'|\\( *'[A-Za-z][A-Za-z0-9-]*'(?: +'[A-Za-z][A-Za-z0-9-]*')* *\\))))?(?: +DESC +(?P<desc>'(?:\\\\5[Cc]|\\\\27|[^'\\\\])+'))?(?P<obsolete> +OBSOLETE)?(?: +SUP +(?P<superclass>(?:(?:[A-Za-z][A-Za-z0-9-]*|[0-9]+(?:\\.[0-9]+)+)|\\( *(?:[A-Za-z][A-Za-z0-9-]*|[0-9]+(?:\\.[0-9]+)+)(?: *\\$ *(?:[A-Za-z][A-Za-z0-9-]*|[0-9]+(?:\\.[0-9]+)+))* *\\))))?(?: +(?P<kind>ABSTRACT|STRUCTURAL|AUXILIARY))?(?: +MUST +(?P<must>(?:(?:[A-Za-z][A-Za-z0-9-]*|[0-9]+(?:\\.[0-9]+)+)|\\( *(?:[A-Za-z][A-Za-z0-9-]*|[0-9]+(?:\\.[0-9]+)+)(?: *\\$ *(?:[A-Za-z][A-Za-z0-9-]*|[0-9]+(?:\\.[0-9]+)+))* *\\))))?(?: +MAY +(?P<may>(?:(?:[A-Za-z][A-Za-z0-9-]*|[0-9]+(?:\\.[0-9]+)+)|\\( *(?:[A-Za-z][A-Za-z0-9-]*|[0-9]+(?:\\.[0-9]+)+)(?: *\\$ *(?:[A-Za-z][A-Za-z0-9-]*|[0-9]+(?:\\.[0-9]+)+))* *\\))))?(?P<extensions> (?:X-[A-Za-z_-]+) (?:'(?:\\\\5[Cc]|\\\\27|[^'\\\\])+'|\\( *'(?:\\\\5[Cc]|\\\\27|[^'\\\\])+'(?: +'(?:\\\\5[Cc]|\\\\27|[^'\\\\])+')* *\\)))? *\\)$"¶
-
-
class
ObjectIdentifierFirstComponentMatch
[source]¶ Bases:
laurelin.ldap.rules.EqualityMatchingRule
-
NAME
= 'objectIdentifierFirstComponentMatch'¶
-
OID
= '2.5.13.30'¶
-
SYNTAX
= '1.3.6.1.4.1.1466.115.121.1.38'¶
-
-
class
ObjectIdentifierMatch
[source]¶ Bases:
laurelin.ldap.rules.EqualityMatchingRule
-
NAME
= 'objectIdentifierMatch'¶
-
OID
= '2.5.13.0'¶
-
SYNTAX
= '1.3.6.1.4.1.1466.115.121.1.38'¶
-
-
class
OctetString
[source]¶ Bases:
laurelin.ldap.rules.SyntaxRule
-
DESC
= 'Octet String'¶
-
OID
= '1.3.6.1.4.1.1466.115.121.1.40'¶
-
validate
(s)[source]¶ Validate a string. Must be implemented by subclasses.
Parameters: s – Candidate string Returns: Any useful value for the rule Raises: InvalidSyntaxError – if the string is invalid
-
-
class
OctetStringMatch
[source]¶ Bases:
laurelin.ldap.rules.EqualityMatchingRule
-
NAME
= 'octetStringMatch'¶
-
OID
= '2.5.13.17'¶
-
SYNTAX
= '1.3.6.1.4.1.1466.115.121.1.40'¶
-
-
class
OtherMailbox
[source]¶ Bases:
laurelin.ldap.rules.RegexSyntaxRule
-
DESC
= 'Other Mailbox'¶
-
OID
= '1.3.6.1.4.1.1466.115.121.1.39'¶
-
regex
= "^[A-Za-z0-9'()+,.=/:? -]+\\$[\\x00-\\x7f]*$"¶
-
-
PAGER
= <AttributeType "pager">¶
-
PERSON
= <ObjectClass "person">¶
-
PERSONAL_TITLE
= <AttributeType "personalTitle">¶
-
PHOTO
= <AttributeType "photo">¶
-
PHYSICAL_DELIVERY_OFFICE_NAME
= <AttributeType "physicalDeliveryOfficeName">¶
-
POSTAL_ADDRESS
= <AttributeType "postalAddress">¶
-
POSTAL_CODE
= <AttributeType "postalCode">¶
-
POST_OFFICE_BOX
= <AttributeType "postOfficeBox">¶
-
PREFERRED_DELIVERY_METHOD
= <AttributeType "preferredDeliveryMethod">¶
-
PREFERRED_LANGUAGE
= <AttributeType "preferredLanguage">¶
-
class
PostalAddress
[source]¶ Bases:
laurelin.ldap.rules.RegexSyntaxRule
-
DESC
= 'Postal Address'¶
-
OID
= '1.3.6.1.4.1.1466.115.121.1.41'¶
-
regex
= '^(\\\\5[cC]|\\\\24|[^\\\\$])+(\\$(\\\\5[cC]|\\\\24|[^\\\\$])+)*$'¶
-
-
class
PrintableString
[source]¶ Bases:
laurelin.ldap.rules.RegexSyntaxRule
-
DESC
= 'Printable String'¶
-
OID
= '1.3.6.1.4.1.1466.115.121.1.44'¶
-
regex
= "^[A-Za-z0-9'()+,.=/:? -]+$"¶
-
-
REGISTERED_ADDRESS
= <AttributeType "registeredAddress">¶
-
RESIDENTIAL_PERSON
= <ObjectClass "residentialPerson">¶
-
RFC822_LOCAL_PORT
= <ObjectClass "rFC822localPart">¶
-
ROLE_OCCUPANT
= <AttributeType "roleOccupant">¶
-
ROOM
= <ObjectClass "room">¶
-
ROOM_NUMBER
= <AttributeType "roomNumber">¶
-
SEARCH_GUIDE
= <AttributeType "searchGuide">¶
-
SECRETARY
= <AttributeType "secretary">¶
-
SEE_ALSO
= <AttributeType "seeAlso">¶
-
SERIAL_NUMBER
= <AttributeType "serialNumber">¶
-
SIMPLE_SECURITY_OBJECT
= <ObjectClass "simpleSecurityObject">¶
-
SN
= <AttributeType "sn">¶
-
ST
= <AttributeType "st">¶
-
STREET
= <AttributeType "street">¶
-
STRUCTURAL_OBJECT_CLASS
= <AttributeType "structuralObjectClass">¶
-
SUBSCHEMA
= <ObjectClass "subschema">¶
-
SUBSCHEMA_SUBENTRY
= <AttributeType "subschemaSubentry">¶
-
SUPPORTED_CONTROL
= <AttributeType "supportedControl">¶
-
SUPPORTED_EXTENSION
= <AttributeType "supportedExtension">¶
-
SUPPORTED_FEATURES
= <AttributeType "supportedFeatures">¶
-
SUPPORTED_LDAP_VERSION
= <AttributeType "supportedLDAPVersion">¶
-
SUPPORTED_SASL_MECHANISMS
= <AttributeType "supportedSASLMechanisms">¶
-
class
SubstringAssertion
[source]¶ Bases:
laurelin.ldap.rules.RegexSyntaxRule
-
DESC
= 'Substring Assertion'¶
-
OID
= '1.3.6.1.4.1.1466.115.121.1.58'¶
-
regex
= '(?:(\\\\2[aA]|\\\\5[cC]|[^*\\\\])+)?\\*(?:(\\\\2[aA]|\\\\5[cC]|[^*\\\\])+\\*)*(?:(\\\\2[aA]|\\\\5[cC]|[^*\\\\])+)?'¶
-
-
TELEPHONE_NUMBER
= <AttributeType "telephoneNumber">¶
-
TELETEX_TERMINAL_IDENTIFIER
= <AttributeType "teletexTerminalIdentifier">¶
-
TELEX_NUMBER
= <AttributeType "telexNumber">¶
-
TITLE
= <AttributeType "title">¶
-
TOP
= <ObjectClass "top">¶
-
class
TelephoneNumber
[source]¶ Bases:
laurelin.ldap.rules.SyntaxRule
-
DESC
= 'Telephone Number'¶
-
OID
= '1.3.6.1.4.1.1466.115.121.1.50'¶
-
validate
(s)[source]¶ Validate a string. Must be implemented by subclasses.
Parameters: s – Candidate string Returns: Any useful value for the rule Raises: InvalidSyntaxError – if the string is invalid
-
-
class
TelephoneNumberMatch
[source]¶ Bases:
laurelin.ldap.rules.EqualityMatchingRule
-
NAME
= 'telephoneNumberMatch'¶
-
OID
= '2.5.13.20'¶
-
SYNTAX
= '1.3.6.1.4.1.1466.115.121.1.50'¶
-
prep_methods
= (<function Transcode>, <function Map.all>, <function Normalize>, <function Prohibit>, <function Insignificant.telephone_number>)¶
-
-
class
TeletextTerminalIdentifier
[source]¶ Bases:
laurelin.ldap.rules.RegexSyntaxRule
-
DESC
= 'Teletex Terminal Identifier'¶
-
OID
= '1.3.6.1.4.1.1466.115.121.1.51'¶
-
regex
= "^[A-Za-z0-9'()+,.=/:? -]+(?:\\$(?:graphic|control|misc|page|private):(?:[\\x00-\\x23]|\\x5c24|\\x5c5C)*)*$"¶
-
-
class
TelexNumber
[source]¶ Bases:
laurelin.ldap.rules.RegexSyntaxRule
-
DESC
= 'Telex Number'¶
-
OID
= '1.3.6.1.4.1.1466.115.121.1.52'¶
-
regex
= "^[A-Za-z0-9'()+,.=/:? -]+\\$[A-Za-z0-9'()+,.=/:? -]+\\$[A-Za-z0-9'()+,.=/:? -]+$"¶
-
-
UID
= <AttributeType "uid">¶
-
UID_OBJECT
= <ObjectClass "uidObject">¶
-
UNIQUE_IDENTIFIER
= <AttributeType "uniqueIdentifier">¶
-
UNIQUE_MEMBER
= <AttributeType "uniqueMember">¶
-
USER_CERTIFICATE
= <AttributeType "userCertificate">¶
-
USER_CLASS
= <AttributeType "userClass">¶
-
USER_PASSWORD
= <AttributeType "userPassword">¶
-
USER_PKCS12
= <AttributeType "userPKCS12">¶
-
USER_SMIME_CERTIFICATE
= <AttributeType "userSMIMECertificate">¶
-
class
UniqueMemberMatch
[source]¶ Bases:
laurelin.ldap.rules.EqualityMatchingRule
-
NAME
= 'uniqueMemberMatch'¶
-
OID
= '2.5.13.23'¶
-
SYNTAX
= '1.3.6.1.4.1.1466.115.121.1.34'¶
-
-
X121_ADDRESS
= <AttributeType "x121Address">¶
-
X500_UNIQUE_IDENTIFIER
= <AttributeType "x500UniqueIdentifier">¶
-
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.descattrs.add({'foo':['one', 'two']})
print(result.format_ldif())
# ...
# description: foo=one
# description: foo=two
# ...
attr_vals = result.descattrs.get_attr('foo')
print(attr_vals)
# ['one', 'two']
result.descattrs.replace({'foo':['one','two','three']})
result.descattrs.delete({'foo':['two']})
attr_vals = result.descattrs.get_attr('foo')
print(attr_vals)
# ['one', 'three']
print(result.format_ldif())
# ...
# description: foo=one
# description: foo=three
# ...
-
laurelin.extensions.descattrs.
DESC_ATTR_DELIM
= '='¶ Key/value delimiter in description attrs. If this character is not present in the description value, then it will be considered unstructured and ignored.
-
class
laurelin.extensions.descattrs.
LaurelinExtension
(modname=None)[source]¶ Bases:
laurelin.ldap.extensible.user_base.BaseLaurelinExtension
-
NAME
= 'descattrs'¶
-
-
class
laurelin.extensions.descattrs.
LaurelinLDAPObjectExtension
(parent)[source]¶ Bases:
laurelin.ldap.extensible.user_base.BaseLaurelinLDAPObjectExtension
-
add
(attrs_dict)[source]¶ Add new description attributes.
Parameters: attrs_dict (dict(str, list[str]) or AttrsDict) – Dictionary of description attributes to add Return type: None
-
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, extensions
with LDAP() as ldap:
ldap.base.obj('ou=netgroups',
tag=extensions.netgroups.TAG,
relative_search_scope=Scope.ONE,
rdn_attr='cn')
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., add_users
) or hosts (e.g. add_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,secrets.example.org)',
]
ldap.netgroups.add_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,secrets.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.netgroups.add_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
-
class
laurelin.extensions.netgroups.
LaurelinExtension
(modname=None)[source]¶ Bases:
laurelin.ldap.extensible.user_base.BaseLaurelinExtension
-
NAME
= 'netgroups'¶
-
TAG
= 'netgroup_base'¶
-
-
class
laurelin.extensions.netgroups.
LaurelinLDAPExtension
(parent)[source]¶ Bases:
laurelin.ldap.extensible.user_base.BaseLaurelinLDAPExtension
-
delete_hosts
(dn, members, domain='')[source]¶ Delete hosts from a netgroup.
Parameters: Return type:
-
delete_users
(dn, members, domain='')[source]¶ Delete users from a netgroup.
Parameters: Return type:
-
get
(cn, attrs=None)[source]¶ Find a specific netgroup object.
This depends on the base object having been tagged and configured properly. See
laurelin.extensions.netgroups
.Parameters: Returns: The netgroup object
Return type: Raises: TagError – if the base object has not been tagged.
-
get_hosts
(cn, recursive=True)[source]¶ 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: Returns: A list of hostnames
Return type: Raises: TagError – if the base object has not been tagged.
-
get_obj_hosts
(ng_obj, recursive=True)[source]¶ 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:
-
get_obj_users
(ng_obj, recursive=True)[source]¶ 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:
-
get_users
(cn, recursive=True)[source]¶ 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: Returns: A list of usernames
Return type: Raises: TagError – if the base object has not been tagged.
-
replace_hosts
(dn, members, domain='')[source]¶ Set new hosts on a netgroup.
Parameters: Return type:
-
replace_users
(dn, members, domain='')[source]¶ Set new users on a netgroup.
Parameters: Return type:
-
search
(filter, attrs=None)[source]¶ Search for netgroups.
This depends on the base object having been tagged and configured properly. See
laurelin.extensions.netgroups
.Parameters: Returns: An iterator over matching netgroup objects, yielding instances of
LDAPObject
.Return type: Raises: TagError – if the base object has not been tagged.
-
-
class
laurelin.extensions.netgroups.
LaurelinLDAPObjectExtension
(parent)[source]¶ Bases:
laurelin.ldap.extensible.user_base.BaseLaurelinLDAPObjectExtension
-
add_hosts
(members, domain='')[source]¶ Add new host netgroup entries to this netgroup object.
Parameters: - 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: Raises: RuntimeError – if this object is missing the netgroup object class
- members (list or str or tuple) – A Member List (see
-
add_users
(members, domain='')[source]¶ Add new user netgroup entries to this netgroup object.
Parameters: - 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: Raises: RuntimeError – if this object is missing the netgroup object class
- members (list or str or tuple) – A Member List (see
-
delete_hosts
(members, domain='')[source]¶ Delete host netgroup entries from this netgroup object.
Parameters: - 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: Raises: RuntimeError – if this object is missing the netgroup object class
- members (list or str or tuple) – A Member List (see
-
delete_users
(members, domain='')[source]¶ Delete user netgroup entries from this netgroup object.
Parameters: - 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: Raises: RuntimeError – if this object is missing the netgroup object class
- members (list or str or tuple) – A Member List (see
-
get_hosts
(recursive=True)[source]¶ 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
-
get_users
(recursive=True)[source]¶ 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
-
replace_hosts
(members, domain='')[source]¶ Set new host netgroup entries on this netgroup object.
Parameters: - 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: Raises: RuntimeError – if this object is missing the netgroup object class
- members (list or str or tuple) – A Member List (see
-
replace_users
(members, domain='')[source]¶ Set new user netgroup entries on this netgroup object.
Parameters: - 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: Raises: RuntimeError – if this object is missing the netgroup object class
- members (list or str or tuple) – A Member List (see
-
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, ''))
-
class
laurelin.extensions.pagedresults.
Cookie
(value=<NoValue object>, **kwargs)[source]¶ Bases:
pyasn1.type.univ.OctetString
-
class
laurelin.extensions.pagedresults.
LaurelinExtension
(modname=None)[source]¶ Bases:
laurelin.ldap.extensible.user_base.BaseLaurelinExtension
-
NAME
= 'paged_results'¶
-
OID
= '1.2.840.113556.1.4.319'¶
-
class
PagedResultsControl
[source]¶ Bases:
laurelin.ldap.controls.Control
-
REQUEST_OID
= '1.2.840.113556.1.4.319'¶
-
RESPONSE_OID
= '1.2.840.113556.1.4.319'¶
-
handle
(ctrl_value)[source]¶ Accepts raw response ctrl_value and may return any useful value.
There is no need to call this base function when overriding.
Parameters: ctrl_value (str) – The string response control value received from the server. Returns: The string ctrl_value unchanged by default. May be overridden to return any relevant value/type/structure.
-
keyword
= 'paged'¶
-
method
= ('search',)¶
-
prepare
(ctrl_value, criticality)[source]¶ Prepare the paged results control value
Parameters: Returns: The protocol-level control object
-
response_attr
= 'page_cookie'¶
-
-
-
class
laurelin.extensions.pagedresults.
RealSearchControlValue
(**kwargs)[source]¶ Bases:
pyasn1.type.univ.Sequence
-
componentType
= <NamedTypes object at 0x7ff3a36d0e10 types <NamedType object at 0x7ff3a340ab00 type size=<Size schema object at 0x7ff3a340a5f8 tagSet <TagSet object at 0x7ff3a39019e8 tags 0:0:2> subtypeSpec <ConstraintsIntersection object at 0x7ff3a38f5278 consts <ValueRangeConstraint object at 0x7ff3a394be80 consts 0, <Integer value object at 0x7ff3a394be48 tagSet <TagSet object at 0x7ff3a39019e8 tags 0:0:2> payload [2147483647]>>>>>, <NamedType object at 0x7ff3a340a0f0 type cookie=<Cookie schema object at 0x7ff3a340a390 encoding iso-8859-1 tagSet <TagSet object at 0x7ff3a38b1438 tags 0:0:4>>>>¶
-
Module contents¶
laurelin.ldap package¶
Submodules¶
Contains base classes for laurelin.ldap
-
class
laurelin.ldap.base.
CompareResponse
(compare_result)[source]¶ Bases:
laurelin.ldap.base.LDAPResponse
Stores boolean compare result and any response control values. The
bool()
of this object gives the compare result.
-
class
laurelin.ldap.base.
ExtendedResponseHandle
(mid, ldap_conn, require_success=False)[source]¶ Bases:
laurelin.ldap.base.ResponseHandle
Obtains rfc4511.ExtendedResponse or rfc4511.IntermediateResponse instances from the server for a particular message ID
-
class
laurelin.ldap.base.
LDAP
(server=None, base_dn=None, reuse_connection=None, connect_timeout=None, search_timeout=None, deref_aliases=None, strict_modify=None, ssl_verify=None, ssl_ca_file=None, ssl_ca_path=None, ssl_ca_data=None, fetch_result_refs=None, default_sasl_mech=None, sasl_fatal_downgrade_check=None, default_criticality=None, follow_referrals=None, validators=None, warn_empty_list=None, error_empty_list=None, ignore_empty_list=None, filter_syntax=None, built_in_extensions_only=None)[source]¶ Bases:
laurelin.ldap.extensible.ldap_extensions.LDAPExtensions
Provides the connection to the LDAP DB. All constructor parameters have a matching global default as a class property on
LDAP
Parameters: - server (str or LDAPSocket) – URI string to connect to or an
LDAPSocket
to reuse - base_dn (str) – The DN of the base object
- reuse_connection (bool) – Allows the socket connection to be reused and reuse an existing socket if possible.
- connect_timeout (int) – Number of seconds to wait for connection to be accepted.
- search_timeout (int) – Number of seconds to wait for a search to complete. Partial results will be returned
when the timeout is reached. Can be overridden on a per-search basis by setting the
search_timeout
keyword onLDAP.search()
. - deref_aliases (DerefAliases) – One of the
DerefAliases
constants. Instructs the server how to handle alias objects in search results. Can be overridden on a per-search basis by setting thederef_aliases
keyword onLDAP.search()
. - strict_modify (bool) – Use the strict modify strategy. If set to True, guarantees that another search will not take place before a modify operation. May potentially produce more server errors.
- ssl_verify (bool) – Validate the certificate and hostname on an SSL/TLS connection
- ssl_ca_file (str) – Path to PEM-formatted concatenated CA certficates file
- ssl_ca_path (str) – Path to directory with CA certs under hashed file names. See https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_load_verify_locations.html for more information about the format of this directory.
- ssl_ca_data (str or bytes) – An ASCII string of one or more PEM-encoded certs or a bytes object containing DER-encoded certificates.
- fetch_result_refs (bool) – Fetch searchResultRef responses in search results. Can be overridden on a per-search
basis by setting the
fetch_result_refs
keyword onLDAP.search()
. - default_sasl_mech (str) – Name of the default SASL mechanism. Bind will fail if the server does not support the mechanism. (Examples: DIGEST-MD5, GSSAPI)
- sasl_fatal_downgrade_check (bool) – Set to False to make potential downgrade attack check non-fatal.
- default_criticality (bool) – Set to True to make controls critical by default, set to False to make non-critical
- follow_referrals (bool) – Automatically follow referral results
- validators (list[Validator]) – A list of
Validator
instances to apply to this connection. - warn_empty_list (bool) – Default False. Set to True to emit a warning when an empty value list is passed to
LDAP.modify()
,LDAP.replace_attrs()
, orLDAP.delete_attrs()
or their LDAPObject counterparts. - error_empty_list (bool) – Default False. Set to True to raise an exception when an empty value list is passed to
LDAP.modify()
,LDAP.replace_attrs()
, orLDAP.delete_attrs()
or their LDAPObject counterparts. - ignore_empty_list (bool) – Default False. Set to True to ignore empty value lists passed to
LDAP.modify()
,LDAP.replace_attrs()
, orLDAP.delete_attrs()
or their LDAPObject counterparts. This will be default True in a future release. - filter_syntax (FilterSyntax) – The default search filter syntax selection. Must be one of the
FilterSyntax
constants. Can be overridden on a per-search basis by setting thefilter_syntax
keyword onLDAP.search()
. Defaults toFilterSyntax.STANDARD
for RFC4515-compliant filter string syntax. - built_in_extensions_only (bool) – Set to True to raise an error when attempting to use a 3rd-party extension
The class can be used as a context manager, which will automatically unbind and close the connection when the context manager exits.
Example:
with LDAP() as ldap: raise Exception() # ldap is closed and unbound with LDAP() as ldap: print('hello') # ldap is closed and unbound
-
DEFAULT_BASE_DN
= None¶
-
DEFAULT_BUILT_IN_EXTENSIONS_ONLY
= False¶
-
DEFAULT_CONNECT_TIMEOUT
= 5¶
-
DEFAULT_CRITICALITY
= False¶
-
DEFAULT_DEREF_ALIASES
= DerefAliases.ALWAYS¶
-
DEFAULT_ERROR_EMPTY_LIST
= False¶
-
DEFAULT_FETCH_RESULT_REFS
= True¶
-
DEFAULT_FILTER
= '(objectClass=*)'¶
-
DEFAULT_FILTER_SYNTAX
= FilterSyntax.UNIFIED¶
-
DEFAULT_FOLLOW_REFERRALS
= True¶
-
DEFAULT_IGNORE_EMPTY_LIST
= True¶
-
DEFAULT_REUSE_CONNECTION
= True¶
-
DEFAULT_SASL_FATAL_DOWNGRADE_CHECK
= True¶
-
DEFAULT_SASL_MECH
= None¶
-
DEFAULT_SEARCH_TIMEOUT
= 0¶
-
DEFAULT_SERVER
= 'ldap://localhost'¶
-
DEFAULT_SSL_CA_DATA
= None¶
-
DEFAULT_SSL_CA_FILE
= None¶
-
DEFAULT_SSL_CA_PATH
= None¶
-
DEFAULT_SSL_VERIFY
= True¶
-
DEFAULT_STRICT_MODIFY
= False¶
-
DEFAULT_VALIDATORS
= None¶
-
DEFAULT_WARN_EMPTY_LIST
= False¶
-
DELETE_ALL
= <delete all values>¶ Use with modify replace/delete in place of an attribute list to delete all values for the attribute
-
LOG_FORMAT
= '[%(asctime)s] %(name)s %(levelname)s : %(message)s'¶
-
NO_ATTRS
= '1.1'¶
-
OID_OBJ_CLASS_ATTR
= '1.3.6.1.4.1.4203.1.5.2'¶
-
OID_STARTTLS
= '1.3.6.1.4.1.1466.20037'¶
-
OID_WHOAMI
= '1.3.6.1.4.1.4203.1.11.3'¶
-
add
(dn, attrs_dict, **kwds)[source]¶ Add new object and return corresponding LDAPObject on success.
Parameters: Returns: The new object
Return type: Raises: - ConnectionUnbound – if the connection has been unbound
- TypeError – if arguments are of invalid type
- LDAPValidationError – if the object fails any configured validator
- LDAPError – if we get a non-success result
Additional keyword arguments are handled as Controls and then passed through into
LDAP.obj()
.
-
add_attrs
(dn, attrs_dict, current=None, **ctrl_kwds)[source]¶ Add new attribute values to existing object.
Parameters: Returns: A response object
Return type: Additional keyword arguments are handled as Controls.
-
static
add_extension
(modname)¶ Import an extension and prepare it for binding under its internally-defined name to LDAP and/or LDAPObject depending which extension classes are defined. This is only needed for extensions not yet patched into AVAILABLE_EXTENSIONS.
Parameters: modname (str) – The string module name containing an extension, can be any importable module, e.g. “laurelin.extensions.netgroups” Return type: None
-
add_if_not_exists
(dn, attrs_dict)[source]¶ Add object if it doesn’t exist
- Gets and returns the object at DN if it exists, otherwise create the object using the attrs dictionary
- Always returns an LDAPObject corresponding to the final state of the DB
Parameters: Returns: The new or existing object
Return type:
-
add_or_mod_add_if_exists
(dn, attrs_dict)[source]¶ Add object if it doesn’t exist, otherwise add_attrs
- If the object at DN exists, perform an add modification using the attrs dictionary. Otherwise, create the object using the attrs dictionary.
- This ensures that, for the attributes mentioned in attrs, AT LEAST those values will exist on the given DN, regardless of prior state of the DB.
- Always returns an
LDAPObject
corresponding to the final state of the DB
Parameters: Returns: The new or modified object
Return type:
-
add_or_mod_replace_if_exists
(dn, attrs_dict)[source]¶ Add object if it doesn’t exist, otherwise replace_attrs
- If the object at DN exists, perform a replace modification using the attrs dictionary Otherwise, create the object using the attrs dictionary
- This ensures that, for the attributes mentioned in attrs, ONLY those values will exist on the given DN regardless of prior state of the DB.
- Always returns an
LDAPObject
corresponding to the final state of the DB
Parameters: Returns: The new or modified object
Return type:
-
close
(force=False)¶ Send an unbind request and close the socket.
Parameters: force (bool) – Unbind and close the socket even if other objects still hold a reference to it. Raises: ConnectionUnbound – if the connection has already been unbound
-
compare
(dn, attr, value, **ctrl_kwds)[source]¶ Ask the server if a particular DN has a matching attribute value. The comparison will take place following the schema-defined matching rules and syntax rules.
Parameters: Returns: A response object,
bool()
evaluating to the result of the comparisonReturn type: Raises: - ConnectionUnbound – if the connection has been unbound
- LDAPError – if we got a result other than compareTrue or compareFalse
Additional keyword arguments are handled as Controls.
-
delete
(dn, **ctrl_kwds)[source]¶ Delete an object.
Parameters: dn (str) – The DN of the object to delete Returns: A response object Return type: LDAPResponse Raises: ConnectionUnbound – if the connection has been unbound Additional keyword arguments are handled as Controls.
-
delete_attrs
(dn, attrs_dict, current=None, **ctrl_kwds)[source]¶ Delete specific attribute values from
attrs_dict
.Specifying a 0-length entry will delete all values.
Parameters: - dn (str) – The DN of the object to modify
- attrs_dict (dict(str, list[str or bytes]) or AttrsDict) – The attributes to remove from the object. Specify an empty list for a value to delete all values.
- current (LDAPObject or None) – The current known state of the object. Used to ensure we don’t request that the server delete attribute values that don’t exist and for validation.
Returns: A response object
Return type: Additional keyword arguments are handled as Controls.
-
disable_validation
(disabled_validators=None)[source]¶ Returns a context manager which temporarily disables validation. If any server errors are generated, they will still be propagated.
Example:
from laurelin.ldap import LDAP from laurelin.ldap.exceptions import LDAPValidationError from laurelin.ldap.schema import SchemaValidator with LDAP(validators=[SchemaValidator()]) as ldap: # make validated queries ldap.base.add_child('cn=foo', {<valid object>}) try: ldap.base.add_child('cn=bar', {<invalid object>}) except LDAPValidationError: pass with ldap.disable_validation(['SchemaValidator']): # make queries without validation ldap.base.add_child('cn=bar', {<invalid object>}) # NOTE: if the object is actually invalid, a server error may still occur # carry on with validation restored...
Parameters: disabled_validators – Optional, a list of string class names or Validator classes to disable. By default all validators will be disabled. Returns: A context manager which temporarily disables validation Return type: DisabledValidationContext
-
static
disable_warnings
()[source]¶ Prevent all LDAP warnings from being shown - default action for others
-
exists
(dn)[source]¶ Simply check if a DN exists.
Parameters: dn (str) – The DN to check Returns: True if the object exists, False if not Return type: bool
-
get
(dn, attrs=None, **kwds)[source]¶ Get a specific object by DN.
Performs a search with
Scope.BASE
and ensures we get exactly one result.Parameters: Returns: The LDAP object
Return type: Raises: - ConnectionUnbound – if the connection has been unbound
- NoSearchResults – if no results are returned
- MultipleSearchResults – if more than one result is returned
Additional keyword arguments are passed through into
LDAP.search()
.
-
get_sasl_mechs
()[source]¶ Query root DSE for supported SASL mechanisms.
Returns: The list of server-supported mechanism names. Return type: list[str]
-
static
log_warnings
()[source]¶ Log all LDAP warnings rather than showing them - default action for others
-
mod_dn
(dn, new_rdn, clean_attr=True, new_parent=None, **ctrl_kwds)[source]¶ Change the DN and possibly the location of an object in the tree. Exposes all options of the protocol-level rfc4511.ModifyDNRequest
Parameters: Returns: A response object
Return type: Raises: ConnectionUnbound – if the connection has been unbound
Additional keyword arguments are handled as Controls.
-
modify
(dn, modlist, current=None, **ctrl_kwds)[source]¶ Perform a series of modify operations on an object atomically
Parameters: - dn (str) – The DN of the object to modify
- modlist (list[Mod]) – A list of
Mod
instances, e.g. [Mod(Mod.ADD, ‘someAttr’, [‘value1’, ‘value2’])] - current (LDAPObject or None) – The current known state of the object for use in validation
Returns: A response object
Return type: Raises: - ConnectionUnbound – if the connection has been unbound
- LDAPValidationError – if the operation fails and configured validator
Additional keyword arguments are handled as Controls.
-
move
(dn, new_dn, clean_attr=True, **ctrl_kwds)[source]¶ Specify a new absolute DN for an object.
Parameters: Returns: A response object
Return type: Additional keyword arguments are handled as Controls.
-
obj
(dn, attrs_dict=None, tag=None, **kwds)[source]¶ Factory for LDAPObjects bound to this connection.
Note that this does not query the server. Use
LDAP.get()
to query the server for a particular DN.Parameters: Returns: The new object bound to this connection.
Return type: Raises: TagError – if the tag parameter is already defined
Additional keywords are passed through into the
LDAPObject
constructor.
-
process_ldif
(ldif_str)[source]¶ Process a basic LDIF
TODO: full RFC 2849 implementation. Missing:
- attribute options
Parameters: ldif_str (str) – An RFC 2849 complying LDIF string
Returns: A list with elements corresponding to the return of each described operation
Return type: Raises: - ValueError – if the LDIF is malformed
- LDAPError – if an unimplemented feature is used
- LDAPSupportError – if a version other than 1 is specified or a critical control is undefined
-
recheck_sasl_mechs
()[source]¶ Query the root DSE again after performing a SASL bind to check for a downgrade attack.
Raises: LDAPError – If the downgrade attack check fails and sasl_fatal_downgrade_check has not been set to False.
-
refresh_root_dse
()[source]¶ Update the local copy of the root DSE, containing metadata about the directory server. The root DSE is an
LDAPObject
stored on the root_dse attribute.
-
rename
(dn, new_rdn, clean_attr=True, **ctrl_kwds)[source]¶ Specify a new RDN for an object without changing its location in the tree.
Parameters: Returns: A response object
Return type: Additional keyword arguments are handled as Controls.
-
replace_attrs
(dn, attrs_dict, current=None, **ctrl_kwds)[source]¶ Replace all values on given attributes with the passed values
- Attributes not mentioned in attrsDict are not touched
- Attributes will be created if they do not exist
- Specifying a 0-length entry will delete all values for that attribute
Parameters: Returns: A response object
Return type: Additional keyword arguments are handled as Controls.
-
sasl_bind
(mech=None, **props)[source]¶ Perform a SASL bind operation.
Keywords are first taken as Controls. Required keyword args are dependent on the mechanism chosen.
Parameters: mech (str) – The SASL mechanism name to use or None to negotiate best mutually supported mechanism.
Returns: A response object
Return type: Raises: - ConnectionUnbound – if the connection has been unbound/closed
- ConnectionAlreadyBound – if the connection has already been bound
- LDAPSupportError – if the given mech is not supported by the server
- LDAPError – if an error occurs during the bind process
-
search
(base_dn, scope=Scope.SUB, filter=None, attrs=None, search_timeout=None, limit=0, deref_aliases=None, attrs_only=False, fetch_result_refs=None, follow_referrals=None, filter_syntax=None, **kwds)[source]¶ Sends search and return an iterator over results.
Parameters: - base_dn (str) – The DN of the base object of the search
- scope (Scope) – One of the
Scope
constants, defaultScope.SUB
. Controls the maximum depth of the search. - filter (str) – A filter string. Objects must match the filter to be included in results. Default includes
all objects and can be overridden globally by defining
LDAP.DEFAULT_FILTER
. - attrs (list[str]) – A list of attribute names to include for each object. Default includes all user attributes. Use [‘*’, ‘+’] to get all user and all operational attributes.
- search_timeout (int) – The number of seconds the server should spend performing the search. Partial results
will be returned if the server times out. The default can be set per connection by
passing the
search_timeout
keyword to theLDAP
constructor, or set the global default by definingLDAP.DEFAULT_SEARCH_TIMEOUT
. - limit (int) – The maximum number of objects to return.
- deref_aliases (DerefAliases) – One of the
DerefAliases
constants. This instructs the server what to do when it encounters an alias object. The default can be set per connection by passing thederef_aliases
keyword to theLDAP
constructor, or set the global default by definingLDAP.DEFAULT_DEREF_ALIASES
. - attrs_only (bool) – Default False. Set to True to only obtain attribute names and not any attribute values.
- fetch_result_refs (bool) – When the server returns a result which is a reference to an object on another
server, automatically attempt to fetch the remote object and include it in the
iterated results. The default can be set per connection by passing the
fetch_result_refs
keyword to theLDAP
constructor, or set the global default by definingLDAP.DEFAULT_FETCH_RESULT_REFS
. - follow_referrals (bool) – When the server knows that the base object is present on another server, follow
the referral and perform the search on the other server. The default can be set
per connection by passing the follow_referrals keyword to the
LDAP
constructor, or set the global default by definingLDAP.DEFAULT_FOLLOW_REFERRALS
. - filter_syntax (FilterSyntax) – Select which filter syntax to use to parse the
filter
. The default can be set per connection by passing thedefault_filter_syntax
keyword to theLDAP
constructor, or set the global default by definingLDAP.DEFAULT_FILTER_SYNTAX
.
Returns: An iterator over the results of the search. May yield
LDAPObject
or possiblySearchReferenceHandle
iffetch_result_refs
is False.Additional keywords are handled as Controls first and then passed through into
LDAP.obj()
.This method may also be used as a context manager. If all results have not been read, the operation will automatically be abandoned when the context manager exits. You can also raise
Abandon
to abandon all results immediately and cleanly exit the context manager. You can also callSearchResultHandle.abandon()
to abandon results.Example:
# Dump the whole tree with LDAP() as ldap: with ldap.base.search() as search: for result in search: print(result.format_ldif())
-
send_extended_request
(oid, value=None, **kwds)[source]¶ Send an extended request, returns instance of
ExtendedResponseHandle
This is mainly meant to be called by other built-in methods and client extensions. Requires handling of raw pyasn1 protocol objects.
Parameters: Returns: An iterator yielding tuples of the form (
rfc4511.IntermediateResponse
,rfc4511.Controls
) or (rfc4511.ExtendedResponse
,rfc4511.Controls
).Return type: Raises: - LDAPSupportError – if the OID is not listed in the supportedExtension attribute of the root DSE
- TypeError – if the value parameter is not a valid type
Additional keyword arguments are handled as Controls and then passed through into the
ExtendedResponseHandle
constructor.
-
simple_bind
(username='', password='', **ctrl_kwds)[source]¶ Performs a simple bind operation
Leave arguments as their default (empty strings) to attempt an anonymous simple bind
Additional keywords are used as Controls.
Parameters: Returns: A response object
Return type: Raises: - ConnectionUnbound – if the connection has been unbound/closed
- ConnectionAlreadyBound – if the connection has already been bound
-
start_tls
(verify=None, ca_file=None, ca_path=None, ca_data=None)[source]¶ Perform the StartTLS extended operation. This will instruct the server to begin encrypting this socket connection with TLS/SSL.
Parameters: - verify (bool) – Set to False to disable verification of the remote certificate. You can set the default
per-connection by passing the ssl_verify keyword to the
LDAP
constructor, or set the global default by definingLDAP.DEFAULT_SSL_VERIFY
. - ca_file (str) – Path to PEM-formatted concatenated CA certficates file. You can set the default
per-connection by passing the ssl_ca_file keyword to the
LDAP
constructor, or set the global default by definingLDAP.DEFAULT_SSL_CA_FILE
. - ca_path (str) – Path to directory with CA certs under hashed file names. See
https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_load_verify_locations.html for more
information about the format of this directory. You can set the default per-connection by
passing the ssl_ca_path keyword to the
LDAP
constructor, or set the global default by definingLDAP.DEFAULT_SSL_CA_PATH
. - ca_data (str or bytes) – An ASCII string of one or more PEM-encoded certs or a bytes object containing DER-encoded
certificates. You can set the default per-connection by passing the ssl_ca_data keyword to the
LDAP
constructor, or set the global default by definingLDAP_DEFAULT_SSL_CA_DATA
.
Return type: - verify (bool) – Set to False to disable verification of the remote certificate. You can set the default
per-connection by passing the ssl_verify keyword to the
-
tag
(tag)[source]¶ Get a tagged object.
Parameters: tag (str) – The tag name to retrieve Returns: The object created with the given tag Return type: LDAPObject Raises: TagError – if the given tag is not defined
-
unbind
(force=False)[source]¶ Send an unbind request and close the socket.
Parameters: force (bool) – Unbind and close the socket even if other objects still hold a reference to it. Raises: ConnectionUnbound – if the connection has already been unbound
-
validate_modify
(dn, modlist, current=None)[source]¶ Run all configured validators for the given modify operation
Parameters: - dn (str) – The DN of the object being modified
- modlist (list[Mod]) – The sequence of changes to be performed
- current (LDAPObject) – The current known state of the object
Return type: Raises: LDAPValidationError – if any validator fails the operation
-
validate_object
(obj, write=True)[source]¶ Run all configured validators for the given object.
Parameters: - obj (LDAPObject) – The object to validate
- write (bool) – True if this is for a write operation (e.g. an add)
Return type: Raises: LDAPValidationError – if any validator fails the object
-
who_am_i
(**ctrl_kwds)[source]¶ Perform the “Who Am I?” extended operation. This will confirm the identity that the connection is bound to.
Returns: A string describing the bound identity. One common form is “dn:cn=foo,dc=example,dc=org” but this will vary by server configuration and bind type/parameters. Return type: str Additional keyword arguments are handled as Controls.
- server (str or LDAPSocket) – URI string to connect to or an
-
class
laurelin.ldap.base.
LDAPResponse
[source]¶ Bases:
object
Empty object for storing response control values
-
class
laurelin.ldap.base.
LDAPURI
(uri)[source]¶ Bases:
object
Represents a parsed LDAP URI as specified in RFC4516
Supported extensions:
- “StartTLS”
Variables: - scheme (str) – urlparse standard
- netloc (str) – urlparse standard
- host_uri (str) – scheme://netloc for use with LDAPSocket
- dn (str) – Distinguished name
- attrs (list[str]) – list
- scope (Scope) – one of the
Scope
constants - filter (str) – The filter string
- starttls (bool) – True if StartTLS was requested
-
DEFAULT_ATTRS
= ['*']¶
-
DEFAULT_FILTER
= '(objectClass=*)'¶
-
DEFAULT_SCOPE
= Scope.BASE¶
-
DEFAULT_STARTTLS
= False¶
-
search
(**kwds)[source]¶ Perform the search operation described by the parsed URI
First opens a new connection with connection reuse disabled, then performs the search, and unbinds the connection. Server must allow anonymous read.
Additional keyword arguments are passed through into
LDAP.search()
.
-
class
laurelin.ldap.base.
ResponseHandle
(ldap_conn, mid)[source]¶ Bases:
laurelin.ldap.base.LDAPResponse
Base for return from methods with multiple response messages.
-
class
laurelin.ldap.base.
SearchReferenceHandle
(uris, obj_kwds)[source]¶ Bases:
object
Returned when the server returns a SearchResultReference
Provides support for establishing an LDAP connection and environment via config files and dicts
-
laurelin.ldap.config.
activate_extensions
(config_dict)[source]¶ Activate the specified extensions. The dict must be formatted as follows:
{'extensions': [ <module name>, ] }
Parameters: config_dict (dict) – See above. Return type: None
-
laurelin.ldap.config.
create_connection
(config_dict)[source]¶ Create a new connection from a config dict formatted as follows:
{'connection': { 'start_tls': <bool>, # optional, default False 'simple_bind': { # optional, default no bind; mutually exclusive with sasl_bind 'username': <string username or bind dn>, 'password': <string password> }, 'sasl_bind': { # optional, default no bind, mutually exclusive with simple_bind 'mech': <standard mech name>, <mech prop>: <mech value>, # required props varies by mech }, <constructor param>: <constructor value>, }, 'objects': [ # optional {'dn': <object dn>, # OR... 'rdn': <dn relative to connection base object>, 'tag': <unique tag name>, <object param>: <object value>, }, # ... ] }
<constructor param>
must be one of theLDAP
constructor keyword arguments.For
validators
you can optionally give the full path to the validator to use as a string, e.g.['laurelin.ldap.schema.SchemaValidator']
For
default_filter_syntax
give one of the strings “STANDARD” or “SIMPLE” (case-insensitive).For objects (optional):
- If the
dn
parameter is specified, it is taken as an absolute DN. - You can specify the
rdn
parameter instead to create the object as a child of the connection’s base object (the base of the tree). - The
tag
parameter is required; this is how created objects are accessed (LDAP.tag()
). - Additional
<object param>
will be passed as keywords toLDAP.obj()
. - If
relative_search_scope
is specified, use one of the strings base, one, or sub. - The server will not be queried to create these objects, so they will have no local attributes. Call
LDAPObject.refresh()
if you need to query attributes.
Note on binding: You can always manually call
LDAP.simple_bind()
orLDAP.sasl_bind()
on theLDAP
instance returned from this method if statically configuring bind credentials is not desirable.Parameters: config_dict – See above. Returns: The new LDAP instance with any objects created and tagged. Raises: TypeError – if any required object parameters are missing - If the
-
laurelin.ldap.config.
load_config_dict
(config_dict)[source]¶ Load config parameters from a dictionary. Must be formatted in the same was as
load_file
Parameters: config_dict (dict) – The config dictionary. See format in load_file
.Returns: The LDAP connection if one was defined, None otherwise Return type: LDAP or None
-
laurelin.ldap.config.
load_file
(path, file_decoder=None)[source]¶ Load a config file. Must decode to dict with all components described on other methods as optional sections/keys. A YAML example:
extensions: - laurelin.extensions.descattrs - laurelin.extensions.netgroups global: SSL_CA_PATH: /etc/ldap/cacerts IGNORE_EMPTY_LIST: true connection: server: ldap://dir01.example.org start_tls: true simple_bind: username: testuser passowrd: testpassword connect_timeout: 30 objects: - rdn: ou=people tag: posix_user_base - rdn: ou=groups tag: posix_group_base - rdn: ou=netgroups tag: netgroup_base
Parameters: - path – A path to a config file. Provides support for YAML and JSON format, or you can specify your own decoder that returns a dict.
- file_decoder – A callable returning a dict when passed a file-like object
Returns: The LDAP connection if one was defined, None otherwise
Return type: Raises: RuntimeError – if an unsupported file extension was given without the
file_decoder
argument.
-
laurelin.ldap.config.
normalize_global_config_param
(key)[source]¶ Normalize a global config key. Does not check validity of the key.
Parameters: key (str) – User-supplied global config key Returns: The normalized key formatted as an attribute of LDAP
Return type: str
-
laurelin.ldap.config.
set_global_config
(global_config_dict)[source]¶ Set the global defaults. The dict must be formatted as follows:
{'global': { <config param>: <config value>, } }
<config param>
must match one of theDEFAULT_
attributes onLDAP
. TheDEFAULT_
prefix is optional and dict keys are case-insensitive. Any parameters not specified will keep the hard-coded default.Parameters: global_config_dict (dict) – See above. Return type: None Raises: KeyError – if the dict is incorrectly formatted or contains unknown config parameters
-
exception
laurelin.ldap.exceptions.
Abandon
[source]¶ Bases:
Exception
Can be raised to cleanly exit a context manager and abandon unread results
-
exception
laurelin.ldap.exceptions.
ConnectionAlreadyBound
[source]¶ Bases:
laurelin.ldap.exceptions.InvalidBindState
Only raised by LDAP.*Bind methods if the connection is already bound when called
-
exception
laurelin.ldap.exceptions.
ConnectionUnbound
[source]¶ Bases:
laurelin.ldap.exceptions.InvalidBindState
Raised when any server operation is attempted after a connection is unbound/closed
-
exception
laurelin.ldap.exceptions.
InvalidBindState
[source]¶ Bases:
laurelin.ldap.exceptions.LDAPError
Base class for exceptions related to bind state
-
exception
laurelin.ldap.exceptions.
InvalidSyntaxError
[source]¶ Bases:
laurelin.ldap.exceptions.LDAPValidationError
Raised when syntax validation fails
-
exception
laurelin.ldap.exceptions.
LDAPConnectionError
[source]¶ Bases:
laurelin.ldap.exceptions.LDAPError
Error occurred creating connection to the LDAP server
-
exception
laurelin.ldap.exceptions.
LDAPError
[source]¶ Bases:
Exception
Base class for all exceptions raised by laurelin
-
exception
laurelin.ldap.exceptions.
LDAPExtensionError
[source]¶ Bases:
laurelin.ldap.exceptions.LDAPError
Error occurred setting up an extension module
-
exception
laurelin.ldap.exceptions.
LDAPSASLError
[source]¶ Bases:
laurelin.ldap.exceptions.LDAPError
Error occurred involving the SASL client
-
exception
laurelin.ldap.exceptions.
LDAPSchemaError
[source]¶ Bases:
laurelin.ldap.exceptions.LDAPError
Error relating to setting up the LDAP schema
-
exception
laurelin.ldap.exceptions.
LDAPSupportError
[source]¶ Bases:
laurelin.ldap.exceptions.LDAPError
A feature is not supported by the server
-
exception
laurelin.ldap.exceptions.
LDAPTransactionError
[source]¶ Bases:
laurelin.ldap.exceptions.LDAPError
Raised by actions not included in a modify transaction
-
exception
laurelin.ldap.exceptions.
LDAPUnicodeWarning
[source]¶ Bases:
laurelin.ldap.exceptions.LDAPWarning
,UnicodeWarning
Warning category for unicode issues relating to LDAP
-
exception
laurelin.ldap.exceptions.
LDAPUnsolicitedMessage
(lm, exc_msg)[source]¶ Bases:
Exception
Raised when a message with ID 0 is returned from the server
This may indicate an incompatability between laurelin and your server distribution and thus is outside the normal exception inheritance chain.
-
exception
laurelin.ldap.exceptions.
LDAPValidationError
[source]¶ Bases:
laurelin.ldap.exceptions.LDAPError
Raised when validation fails
-
exception
laurelin.ldap.exceptions.
LDAPWarning
[source]¶ Bases:
Warning
Generic LDAP warning category
-
exception
laurelin.ldap.exceptions.
MultipleSearchResults
[source]¶ Bases:
laurelin.ldap.exceptions.UnexpectedSearchResults
Got multiple search results when exactly one was required
-
exception
laurelin.ldap.exceptions.
NoSearchResults
[source]¶ Bases:
laurelin.ldap.exceptions.UnexpectedSearchResults
Got no search results when one or more was required
-
exception
laurelin.ldap.exceptions.
ProhibitedCharacterError
[source]¶ Bases:
laurelin.ldap.exceptions.LDAPError
Raised when a prohibited character is detected in RFC4518 string prep
-
exception
laurelin.ldap.exceptions.
TagError
[source]¶ Bases:
laurelin.ldap.exceptions.LDAPError
Error with an object tag
-
exception
laurelin.ldap.exceptions.
UnexpectedResponseType
[source]¶ Bases:
laurelin.ldap.exceptions.LDAPError
The response did not contain the expected protocol operation
-
exception
laurelin.ldap.exceptions.
UnexpectedSearchResults
[source]¶ Bases:
laurelin.ldap.exceptions.LDAPError
Base class for unhandled search result situations
-
class
laurelin.ldap.ldapobject.
LDAPObject
(dn, attrs_dict=None, ldap_conn=None, relative_search_scope=Scope.SUB, rdn_attr=None)[source]¶ Bases:
laurelin.ldap.attrsdict.AttrsDict
,laurelin.ldap.extensible.ldapobject_extensions.LDAPObjectExtensions
Represents a single object with optional server affinity.
Many methods will raise an exception if used without a server connection. To instantiate an
LDAPObject
bound to a server connection, useLDAP.obj()
.Attributes and values are stored using the mapping interface inherited from AttrsDict, where dict keys are case-insensitive attribute names, and dict values are a list of attribute values.
Value lists are automatically wrapped in
AttrValueList
. This allows the use of any schema-defined matching and syntax rules for the attribute type in list operations.Parameters: - dn (str) – The DN of the object
- attrs_dict (dict(str, list[str or bytes]) or AttrsDict or None) – The object’s attributes
- ldap_conn (LDAP or None) – The optional LDAP connection to use
- relative_search_scope (Scope) – One of the
Scope
constants, this is the default scope used when using this object’sLDAPObject.search()
method. New objects created below this one will inherit this attribute by default. This attribute also defines the behavior ofLDAPObject.find()
. - rdn_attr (str or None) – The default attribute name used in RDN’s for descendents of this object. If specified, this
allows you to only specify the value for methods that have an
rdn
argument. You can always specify a full attr=value forrdn
arguments as well to override this behavior. New objects created below this one will inherit this attribute by default.
-
add_attrs
(attrs_dict, **ctrl_kwds)[source]¶ Add new attribute values to this object.
Parameters: attrs_dict (dict(str, list[str or bytes]) or AttrsDict) – The new attributes to add to the object Return type: None Additional keywords are passed through into
LDAPObject.modify()
.
-
add_child
(rdn, attrs_dict, **kwds)[source]¶ Create a new object below this one.
Parameters: Returns: The new object
Return type: Additional keyword arguments are passed through into
LDAP.add()
-
compare
(attr, value)[source]¶ Ask the server if this object has a matching attribute value. The comparison will take place following the schema-defined matching rules and syntax rules.
Parameters: Returns: A response object,
bool()
evaluating to the result of the comparisonReturn type: Raises: RuntimeError – if this object is not bound to an LDAP connection
-
delete
(**ctrl_kwds)[source]¶ Delete the entire object from the server, and render this instance useless.
Additional keywords are passed through into
LDAP.delete()
.Return type: None Raises: RuntimeError – if this object is not bound to an LDAP connection
-
delete_attrs
(attrs_dict, **ctrl_kwds)[source]¶ Delete specifc attribute values given in
attrs_dict
. Specifying a zero-length list for any attribute will delete all values for that attribute.Parameters: attrs_dict (dict(str, list[str or bytes]) or AttrsDict) – The attributes to delete from the object Return type: None Additional keywords are passed through into
LDAPObject.modify()
.
-
delete_child
(rdn, **ctrl_kwds)[source]¶ Delete a child object below this one.
Parameters: rdn (str) – The RDN, or RDN value if rdn_attr is defined for this object Returns: The LDAPResponse
from the delete operationReturn type: LDAPResponse Additional keyword arguments are treated as controls.
-
find
(rdn, attrs=None, **kwds)[source]¶ Obtain a single object below this one with the most efficient means possible.
The strategy used is based on the
relative_search_scope
property of this object.- If it is
Scope.BASE
, this method will always raise anLDAPError
. - If it is
Scope.ONE
, then the absolute DN for the child object will be constructed, and aScope.BASE
search will be performed to get the object. - If it is
Scope.SUB
, then a subtree search will be performed below this object, using the RDN as a search filter.
Additional keywords are passed through into
LDAPObject.search()
.Parameters: Returns: The LDAP object
Return type: Raises: - LDAPError – if this object’s
relative_search_scope
isScope.BASE
. - NoSearchResults – if no object could be found matching
rdn
. - MultipleSearchResults – if more than one object was found.
- RuntimeError – if this object is not bound to an LDAP connection
- ValueError – if the
relative_search_scope
is set to an invalid value.
- If it is
-
format_ldif
()[source]¶ Format the object as an LDIF string.
Returns: The object encoded as an LDIF. Return type: str
-
get_child
(rdn, attrs=None, **kwds)[source]¶ Query the server for a child object.
Parameters: Returns: The object populated with data from the server
Return type: Raises: RuntimeError – if this object is not bound to an LDAP connection
Additional keywords are passed through into
LDAP.search()
andLDAPObject
-
has_object_class
(object_class)[source]¶ A convenience method which checks if this object has a particular objectClass. May query the server for the objectClass attribute if it is not yet known.
Parameters: object_class – The objectClass to check for. Returns: True if the objectClass is present, False otherwise Return type: bool
-
mod_dn
(new_rdn, clean_attr=True, new_parent=None, **ctrl_kwds)[source]¶ Change the object DN, and possibly its location in the tree.
Parameters: Return type: Raises: RuntimeError – if this object is not bound to an LDAP connection
Additional keywords are passed through into
LDAP.mod_dn()
.
-
mod_transaction
()[source]¶ Begin a modify transaction on this object. Important: This IS NOT an RFC 5805 transaction.
Return type: ModTransactionObject
-
modify
(modlist, **ctrl_kwds)[source]¶ Perform a series of modify operations on this object atomically.
Parameters: modlist (list[Mod]) – A list of Mod
instances, e.g. [Mod(Mod.ADD, ‘someAttr’, [‘value1’, ‘value2’])]Return type: None Raises: RuntimeError – if this object is not bound to an LDAP connection Additional keywords are passed through into
LDAP.modify()
.
-
move
(new_dn, clean_attr=True, **ctrl_kwds)[source]¶ Specify the complete new absolute DN for this object.
Parameters: Return type: Additional keywords are passed through into
LDAPObject.mod_dn()
.
-
obj
(rdn, attrs_dict=None, tag=None, **kwds)[source]¶ Create a new object below this one.
Parameters: Returns: The new object
Return type: Raises: LDAPError – if a
tag
is specified but this object is not bound to an LDAP connectionAdditional keywords are passed through into
LDAP.obj()
. or theLDAPObject
constructor.
-
rdn
(rdn)[source]¶ Return an absolute DN from an RDN or RDN value
Parameters: rdn (str) – The RDN, or RDN value if rdn_attr is defined for this object Returns: The absolute DN Return type: str
-
refresh
(attrs=None)[source]¶ Query the server to update the attributes on this object.
Parameters: attrs (list[str]) – Optional. A list of attribute names to query. If not specified, will query the server for all user attributes. Return type: None Raises: RuntimeError – if this object is not bound to an LDAP connection
-
refresh_all
()[source]¶ Query the server to update all user and operational attributes on this object.
Return type: None Raises: RuntimeError – if this object is not bound to an LDAP connection
-
refresh_missing
(attrs)[source]¶ Potentially query the server for any listed attributes that are not yet defined on this object. If no listed attributes aren’t defined, the query will not be performed. If a subset of the list is undefined, only those attributes will be queried.
Parameters: attrs (list[str]) – A list of attribute names to check, and possibly query for. Return type: None
-
rename
(new_rdn, clean_attr=True, **ctrl_kwds)[source]¶ Change the object’s RDN without changing it’s location in the tree.
Parameters: Return type: Additional keywords are passed through into
LDAPObject.mod_dn()
.
-
replace_attrs
(attrs_dict, **ctrl_kwds)[source]¶ Replace all values on the given attributes with the passed values.
Parameters: attrs_dict (dict(str, list[str or bytes]) or AttrsDict) – The new attributes to set on the object Return type: None Additional keywords are passed through into
LDAPObject.modify()
.
-
search
(filter=None, attrs=None, **kwds)[source]¶ Perform a search below this object.
Parameters: Returns: An iterator over
LDAPObject
and possiblySearchReferenceHandle
. SeeLDAP.search()
for more details.Return type: Additional keywords are passed through into
LDAP.search()
.
-
class
laurelin.ldap.ldapobject.
ModTransactionObject
(ldap_object)[source]¶ Bases:
laurelin.ldap.ldapobject.LDAPObject
Provides a transaction-like construct for building up a single modify operation. Users should use
LDAPObject.mod_transaction()
rather than instantiating this directly.Inherits all modify methods from
LDAPObject
, allowing users to utilize the familiar interface for modifications, but overrides the basemodify
method so that changes are not immediately applied on the server.The state of attributes is mutated within this transaction object with each higher-level modify call (e.g.,
LDAPObject.add_attrs()
) allowing the state to be inspected. WhenModTransactionObject.commit()
is invoked, the built-up series of raw modify operations is sent to the server, and the state of the underlyingLDAPObject
is mutated.Since this ultimately constructs only one modify operation per commit, the transaction is atomic.
You can also call
mod_transaction()
on a transaction object to create a “checkpoint”. The local state of the transaction will be copied into a new transaction object. To “roll back”, just delete the new object without committing.Example:
from laurelin.ldap import LDAP with LDAP() as ldap: obj = ldap.base.get_child('cn=someobject') print(obj.get_attr('memberUid')) # ['foo', 'bar'] with obj.mod_transaction() as trans: trans.add_attrs({'memberUid': ['foobar']}) print(trans.get_attr('memberUid')) # ['foo', 'bar', 'foobar'] print(obj.get_attr('memberUid')) # ['foo', 'bar'] trans.delete_attrs({'memberUid': ['bar']}) print(trans.get_attr('memberUid')) # ['foo', 'foobar'] print(obj.get_attr('memberUid')) # ['foo', 'bar'] with trans.mod_transaction() as checkpoint: print(checkpoint.get_attr('memberUid')) # ['foo', 'foobar'] print(trans.get_attr('memberUid')) # ['foo', 'foobar'] print(obj.get_attr('memberUid')) # ['foo', 'bar'] checkpoint.delete_attrs({'memberUid': ['foo']}) print(checkpoint.get_attr('memberUid')) # ['foobar'] print(trans.get_attr('memberUid')) # ['foo', 'foobar'] print(obj.get_attr('memberUid')) # ['foo', 'bar'] # Note: no commit on checkpoint, meaning we will be rolled back to the pre-checkpoint state # Now in rolled-back (actually just unchanged) state print(trans.get_attr('memberUid')) # ['foo', 'foobar'] print(obj.get_attr('memberUid')) # ['foo', 'bar'] trans.commit() # Transaction was committed, we can now see changes reflected in the original object: print(obj.get_attr('memberUid')) # ['foo', 'foobar']
You can also raise
Abandon
from within a transaction context manager to cleanly abandon the transaction and exit the context manager.-
add_child
(rdn, attrs_dict, **kwds)[source]¶ Raises an error if used in a transaction. Transactions can only modify one object at a time.
Raises: LDAPTransactionError – if this method is called.
-
commit
()[source]¶ Send the modify operation to the server and update the original local
LDAPObject
.Return type: None
-
delete
(**ctrl_kwds)[source]¶ Raises an error if used in a transaction. Transactions can only modify one object at a time.
Raises: LDAPTransactionError – if this method is called.
-
delete_child
(rdn, **ctrl_kwds)[source]¶ Raises an error if used in a transaction. Transactions can only modify one object at a time.
Raises: LDAPTransactionError – if this method is called
-
format_mod_ldif
()[source]¶ Format the modify operation as an LDIF
Returns: The LDIF string describing the modify operation to be performed Return type: str
-
mod_dn
(new_rdn, clean_attr=True, new_parent=None, **ctrl_kwds)[source]¶ Raises an error if used in a transaction. Transactions can only modify one object at a time.
Raises: LDAPTransactionError – if this method is called.
-
modify
(modlist, **kwds)[source]¶ Process and validate a partial transaction, and mutate the transaction object’s local attributes. Does not send anything to the server.
Parameters: modlist (list[Mod]) – A partial list of modify operations to include in the transaction. Return type: None Raises: TypeError – if any extra keyword arguments are passed to this function.
-
Module contents¶
Imports and defines the core of the public API
-
laurelin.ldap.
get_attribute_type
(ident)[source]¶ Get an instance of
AttributeType
associated with either a name or OID.Parameters: ident (str) – Either the numeric OID of the desired attribute type spec or any one of its specified names Returns: The AttributeType containing a parsed specification Return type: AttributeType
-
class
laurelin.ldap.
AttributeType
(spec)[source]¶ Bases:
object
Parses an LDAP attribute type specification and implements supertype inheritance.
Each instantiation registers the names and OIDs specified so that the spec can be accessed using
get_attribute_type()
.See the
laurelin.ldap.schema
module source for example usages.Parameters: spec (str) – The LDAP specification for an Attribute Type.
Raises: LDAPSchemaError: * if the specification is invalid * if the OID has already been defined * if one of the names has already been defined
Variables: - oid (str) – The OID of the attribute type
- names (tuple(str)) – A tuple containing all possible names for the attribute type
- supertype (str) – The specified supertype. If the spec does not define optional properties, they will pass through into the supertype.
- equality_oid (str) – The OID of the equality matching rule
- syntax_oid (str) – The OID of the syntax matching rule
- syntax_length (int) – The suggested maximum length of a value
- obsolete (bool) – The type has been flagged as obsolete. Will cause a warning from the
SchemaValidator
if an obsolete attribute type is used. - single_value (bool) – The attribute may only have one value.
- collective (bool) – The attribute has been marked collective.
- no_user_mod (bool) – The attribute may not be modified by users (e.g., for operational attributes). Will cause a
validation failure from the
SchemaValidator
if a write operation is attempted on attribute types with this property set to True. - usage (str) – A string describing the attribute’s usage. May be one of userApplications, directoryOperation, distributedOperation, or dSAOperation.
-
equality
¶ Gets the
EqualityMatchingRule
for this attribute type.
-
index
(value_list, assertion_value)[source]¶ Finds the index of a value in a list of attribute values. Raises a ValueError if the value is not found in the list. Assumes values in value_list are already validated.
Parameters: Returns: The index of
assertion_value
invalue_list
.Return type: Raises: - ValueError – if
assertion_value
is not found or ifvalue_list
is empty. - InvalidSyntaxError – if
assertion_value
does not meet the syntax requirements of this attribute type
- ValueError – if
-
syntax
¶ Gets the
SyntaxRule
for this attribute type.
-
validate
(value)[source]¶ Validate a value according to the attribute type’s syntax rule.
Parameters: value (str) – The potential attribute value Returns: A truthy value. Raises: InvalidSyntaxError – if the value is invalid.
-
class
laurelin.ldap.
LDAP
(server=None, base_dn=None, reuse_connection=None, connect_timeout=None, search_timeout=None, deref_aliases=None, strict_modify=None, ssl_verify=None, ssl_ca_file=None, ssl_ca_path=None, ssl_ca_data=None, fetch_result_refs=None, default_sasl_mech=None, sasl_fatal_downgrade_check=None, default_criticality=None, follow_referrals=None, validators=None, warn_empty_list=None, error_empty_list=None, ignore_empty_list=None, filter_syntax=None, built_in_extensions_only=None)[source]¶ Bases:
laurelin.ldap.extensible.ldap_extensions.LDAPExtensions
Provides the connection to the LDAP DB. All constructor parameters have a matching global default as a class property on
LDAP
Parameters: - server (str or LDAPSocket) – URI string to connect to or an
LDAPSocket
to reuse - base_dn (str) – The DN of the base object
- reuse_connection (bool) – Allows the socket connection to be reused and reuse an existing socket if possible.
- connect_timeout (int) – Number of seconds to wait for connection to be accepted.
- search_timeout (int) – Number of seconds to wait for a search to complete. Partial results will be returned
when the timeout is reached. Can be overridden on a per-search basis by setting the
search_timeout
keyword onLDAP.search()
. - deref_aliases (DerefAliases) – One of the
DerefAliases
constants. Instructs the server how to handle alias objects in search results. Can be overridden on a per-search basis by setting thederef_aliases
keyword onLDAP.search()
. - strict_modify (bool) – Use the strict modify strategy. If set to True, guarantees that another search will not take place before a modify operation. May potentially produce more server errors.
- ssl_verify (bool) – Validate the certificate and hostname on an SSL/TLS connection
- ssl_ca_file (str) – Path to PEM-formatted concatenated CA certficates file
- ssl_ca_path (str) – Path to directory with CA certs under hashed file names. See https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_load_verify_locations.html for more information about the format of this directory.
- ssl_ca_data (str or bytes) – An ASCII string of one or more PEM-encoded certs or a bytes object containing DER-encoded certificates.
- fetch_result_refs (bool) – Fetch searchResultRef responses in search results. Can be overridden on a per-search
basis by setting the
fetch_result_refs
keyword onLDAP.search()
. - default_sasl_mech (str) – Name of the default SASL mechanism. Bind will fail if the server does not support the mechanism. (Examples: DIGEST-MD5, GSSAPI)
- sasl_fatal_downgrade_check (bool) – Set to False to make potential downgrade attack check non-fatal.
- default_criticality (bool) – Set to True to make controls critical by default, set to False to make non-critical
- follow_referrals (bool) – Automatically follow referral results
- validators (list[Validator]) – A list of
Validator
instances to apply to this connection. - warn_empty_list (bool) – Default False. Set to True to emit a warning when an empty value list is passed to
LDAP.modify()
,LDAP.replace_attrs()
, orLDAP.delete_attrs()
or their LDAPObject counterparts. - error_empty_list (bool) – Default False. Set to True to raise an exception when an empty value list is passed to
LDAP.modify()
,LDAP.replace_attrs()
, orLDAP.delete_attrs()
or their LDAPObject counterparts. - ignore_empty_list (bool) – Default False. Set to True to ignore empty value lists passed to
LDAP.modify()
,LDAP.replace_attrs()
, orLDAP.delete_attrs()
or their LDAPObject counterparts. This will be default True in a future release. - filter_syntax (FilterSyntax) – The default search filter syntax selection. Must be one of the
FilterSyntax
constants. Can be overridden on a per-search basis by setting thefilter_syntax
keyword onLDAP.search()
. Defaults toFilterSyntax.STANDARD
for RFC4515-compliant filter string syntax. - built_in_extensions_only (bool) – Set to True to raise an error when attempting to use a 3rd-party extension
The class can be used as a context manager, which will automatically unbind and close the connection when the context manager exits.
Example:
with LDAP() as ldap: raise Exception() # ldap is closed and unbound with LDAP() as ldap: print('hello') # ldap is closed and unbound
-
DEFAULT_BASE_DN
= None¶
-
DEFAULT_BUILT_IN_EXTENSIONS_ONLY
= False¶
-
DEFAULT_CONNECT_TIMEOUT
= 5¶
-
DEFAULT_CRITICALITY
= False¶
-
DEFAULT_DEREF_ALIASES
= DerefAliases.ALWAYS¶
-
DEFAULT_ERROR_EMPTY_LIST
= False¶
-
DEFAULT_FETCH_RESULT_REFS
= True¶
-
DEFAULT_FILTER
= '(objectClass=*)'¶
-
DEFAULT_FILTER_SYNTAX
= FilterSyntax.UNIFIED¶
-
DEFAULT_FOLLOW_REFERRALS
= True¶
-
DEFAULT_IGNORE_EMPTY_LIST
= True¶
-
DEFAULT_REUSE_CONNECTION
= True¶
-
DEFAULT_SASL_FATAL_DOWNGRADE_CHECK
= True¶
-
DEFAULT_SASL_MECH
= None¶
-
DEFAULT_SEARCH_TIMEOUT
= 0¶
-
DEFAULT_SERVER
= 'ldap://localhost'¶
-
DEFAULT_SSL_CA_DATA
= None¶
-
DEFAULT_SSL_CA_FILE
= None¶
-
DEFAULT_SSL_CA_PATH
= None¶
-
DEFAULT_SSL_VERIFY
= True¶
-
DEFAULT_STRICT_MODIFY
= False¶
-
DEFAULT_VALIDATORS
= None¶
-
DEFAULT_WARN_EMPTY_LIST
= False¶
-
DELETE_ALL
= <delete all values>¶ Use with modify replace/delete in place of an attribute list to delete all values for the attribute
-
LOG_FORMAT
= '[%(asctime)s] %(name)s %(levelname)s : %(message)s'¶
-
NO_ATTRS
= '1.1'¶
-
OID_OBJ_CLASS_ATTR
= '1.3.6.1.4.1.4203.1.5.2'¶
-
OID_STARTTLS
= '1.3.6.1.4.1.1466.20037'¶
-
OID_WHOAMI
= '1.3.6.1.4.1.4203.1.11.3'¶
-
add
(dn, attrs_dict, **kwds)[source]¶ Add new object and return corresponding LDAPObject on success.
Parameters: Returns: The new object
Return type: Raises: - ConnectionUnbound – if the connection has been unbound
- TypeError – if arguments are of invalid type
- LDAPValidationError – if the object fails any configured validator
- LDAPError – if we get a non-success result
Additional keyword arguments are handled as Controls and then passed through into
LDAP.obj()
.
-
add_attrs
(dn, attrs_dict, current=None, **ctrl_kwds)[source]¶ Add new attribute values to existing object.
Parameters: Returns: A response object
Return type: Additional keyword arguments are handled as Controls.
-
static
add_extension
(modname)¶ Import an extension and prepare it for binding under its internally-defined name to LDAP and/or LDAPObject depending which extension classes are defined. This is only needed for extensions not yet patched into AVAILABLE_EXTENSIONS.
Parameters: modname (str) – The string module name containing an extension, can be any importable module, e.g. “laurelin.extensions.netgroups” Return type: None
-
add_if_not_exists
(dn, attrs_dict)[source]¶ Add object if it doesn’t exist
- Gets and returns the object at DN if it exists, otherwise create the object using the attrs dictionary
- Always returns an LDAPObject corresponding to the final state of the DB
Parameters: Returns: The new or existing object
Return type:
-
add_or_mod_add_if_exists
(dn, attrs_dict)[source]¶ Add object if it doesn’t exist, otherwise add_attrs
- If the object at DN exists, perform an add modification using the attrs dictionary. Otherwise, create the object using the attrs dictionary.
- This ensures that, for the attributes mentioned in attrs, AT LEAST those values will exist on the given DN, regardless of prior state of the DB.
- Always returns an
LDAPObject
corresponding to the final state of the DB
Parameters: Returns: The new or modified object
Return type:
-
add_or_mod_replace_if_exists
(dn, attrs_dict)[source]¶ Add object if it doesn’t exist, otherwise replace_attrs
- If the object at DN exists, perform a replace modification using the attrs dictionary Otherwise, create the object using the attrs dictionary
- This ensures that, for the attributes mentioned in attrs, ONLY those values will exist on the given DN regardless of prior state of the DB.
- Always returns an
LDAPObject
corresponding to the final state of the DB
Parameters: Returns: The new or modified object
Return type:
-
close
(force=False)¶ Send an unbind request and close the socket.
Parameters: force (bool) – Unbind and close the socket even if other objects still hold a reference to it. Raises: ConnectionUnbound – if the connection has already been unbound
-
compare
(dn, attr, value, **ctrl_kwds)[source]¶ Ask the server if a particular DN has a matching attribute value. The comparison will take place following the schema-defined matching rules and syntax rules.
Parameters: Returns: A response object,
bool()
evaluating to the result of the comparisonReturn type: Raises: - ConnectionUnbound – if the connection has been unbound
- LDAPError – if we got a result other than compareTrue or compareFalse
Additional keyword arguments are handled as Controls.
-
delete
(dn, **ctrl_kwds)[source]¶ Delete an object.
Parameters: dn (str) – The DN of the object to delete Returns: A response object Return type: LDAPResponse Raises: ConnectionUnbound – if the connection has been unbound Additional keyword arguments are handled as Controls.
-
delete_attrs
(dn, attrs_dict, current=None, **ctrl_kwds)[source]¶ Delete specific attribute values from
attrs_dict
.Specifying a 0-length entry will delete all values.
Parameters: - dn (str) – The DN of the object to modify
- attrs_dict (dict(str, list[str or bytes]) or AttrsDict) – The attributes to remove from the object. Specify an empty list for a value to delete all values.
- current (LDAPObject or None) – The current known state of the object. Used to ensure we don’t request that the server delete attribute values that don’t exist and for validation.
Returns: A response object
Return type: Additional keyword arguments are handled as Controls.
-
disable_validation
(disabled_validators=None)[source]¶ Returns a context manager which temporarily disables validation. If any server errors are generated, they will still be propagated.
Example:
from laurelin.ldap import LDAP from laurelin.ldap.exceptions import LDAPValidationError from laurelin.ldap.schema import SchemaValidator with LDAP(validators=[SchemaValidator()]) as ldap: # make validated queries ldap.base.add_child('cn=foo', {<valid object>}) try: ldap.base.add_child('cn=bar', {<invalid object>}) except LDAPValidationError: pass with ldap.disable_validation(['SchemaValidator']): # make queries without validation ldap.base.add_child('cn=bar', {<invalid object>}) # NOTE: if the object is actually invalid, a server error may still occur # carry on with validation restored...
Parameters: disabled_validators – Optional, a list of string class names or Validator classes to disable. By default all validators will be disabled. Returns: A context manager which temporarily disables validation Return type: DisabledValidationContext
-
static
disable_warnings
()[source]¶ Prevent all LDAP warnings from being shown - default action for others
-
exists
(dn)[source]¶ Simply check if a DN exists.
Parameters: dn (str) – The DN to check Returns: True if the object exists, False if not Return type: bool
-
get
(dn, attrs=None, **kwds)[source]¶ Get a specific object by DN.
Performs a search with
Scope.BASE
and ensures we get exactly one result.Parameters: Returns: The LDAP object
Return type: Raises: - ConnectionUnbound – if the connection has been unbound
- NoSearchResults – if no results are returned
- MultipleSearchResults – if more than one result is returned
Additional keyword arguments are passed through into
LDAP.search()
.
-
get_sasl_mechs
()[source]¶ Query root DSE for supported SASL mechanisms.
Returns: The list of server-supported mechanism names. Return type: list[str]
-
static
log_warnings
()[source]¶ Log all LDAP warnings rather than showing them - default action for others
-
mod_dn
(dn, new_rdn, clean_attr=True, new_parent=None, **ctrl_kwds)[source]¶ Change the DN and possibly the location of an object in the tree. Exposes all options of the protocol-level rfc4511.ModifyDNRequest
Parameters: Returns: A response object
Return type: Raises: ConnectionUnbound – if the connection has been unbound
Additional keyword arguments are handled as Controls.
-
modify
(dn, modlist, current=None, **ctrl_kwds)[source]¶ Perform a series of modify operations on an object atomically
Parameters: Returns: A response object
Return type: Raises: - ConnectionUnbound – if the connection has been unbound
- LDAPValidationError – if the operation fails and configured validator
Additional keyword arguments are handled as Controls.
-
move
(dn, new_dn, clean_attr=True, **ctrl_kwds)[source]¶ Specify a new absolute DN for an object.
Parameters: Returns: A response object
Return type: Additional keyword arguments are handled as Controls.
-
obj
(dn, attrs_dict=None, tag=None, **kwds)[source]¶ Factory for LDAPObjects bound to this connection.
Note that this does not query the server. Use
LDAP.get()
to query the server for a particular DN.Parameters: Returns: The new object bound to this connection.
Return type: Raises: TagError – if the tag parameter is already defined
Additional keywords are passed through into the
LDAPObject
constructor.
-
process_ldif
(ldif_str)[source]¶ Process a basic LDIF
TODO: full RFC 2849 implementation. Missing:
- attribute options
Parameters: ldif_str (str) – An RFC 2849 complying LDIF string
Returns: A list with elements corresponding to the return of each described operation
Return type: Raises: - ValueError – if the LDIF is malformed
- LDAPError – if an unimplemented feature is used
- LDAPSupportError – if a version other than 1 is specified or a critical control is undefined
-
recheck_sasl_mechs
()[source]¶ Query the root DSE again after performing a SASL bind to check for a downgrade attack.
Raises: LDAPError – If the downgrade attack check fails and sasl_fatal_downgrade_check has not been set to False.
-
refresh_root_dse
()[source]¶ Update the local copy of the root DSE, containing metadata about the directory server. The root DSE is an
LDAPObject
stored on the root_dse attribute.
-
rename
(dn, new_rdn, clean_attr=True, **ctrl_kwds)[source]¶ Specify a new RDN for an object without changing its location in the tree.
Parameters: Returns: A response object
Return type: Additional keyword arguments are handled as Controls.
-
replace_attrs
(dn, attrs_dict, current=None, **ctrl_kwds)[source]¶ Replace all values on given attributes with the passed values
- Attributes not mentioned in attrsDict are not touched
- Attributes will be created if they do not exist
- Specifying a 0-length entry will delete all values for that attribute
Parameters: Returns: A response object
Return type: Additional keyword arguments are handled as Controls.
-
sasl_bind
(mech=None, **props)[source]¶ Perform a SASL bind operation.
Keywords are first taken as Controls. Required keyword args are dependent on the mechanism chosen.
Parameters: mech (str) – The SASL mechanism name to use or None to negotiate best mutually supported mechanism.
Returns: A response object
Return type: Raises: - ConnectionUnbound – if the connection has been unbound/closed
- ConnectionAlreadyBound – if the connection has already been bound
- LDAPSupportError – if the given mech is not supported by the server
- LDAPError – if an error occurs during the bind process
-
search
(base_dn, scope=Scope.SUB, filter=None, attrs=None, search_timeout=None, limit=0, deref_aliases=None, attrs_only=False, fetch_result_refs=None, follow_referrals=None, filter_syntax=None, **kwds)[source]¶ Sends search and return an iterator over results.
Parameters: - base_dn (str) – The DN of the base object of the search
- scope (Scope) – One of the
Scope
constants, defaultScope.SUB
. Controls the maximum depth of the search. - filter (str) – A filter string. Objects must match the filter to be included in results. Default includes
all objects and can be overridden globally by defining
LDAP.DEFAULT_FILTER
. - attrs (list[str]) – A list of attribute names to include for each object. Default includes all user attributes. Use [‘*’, ‘+’] to get all user and all operational attributes.
- search_timeout (int) – The number of seconds the server should spend performing the search. Partial results
will be returned if the server times out. The default can be set per connection by
passing the
search_timeout
keyword to theLDAP
constructor, or set the global default by definingLDAP.DEFAULT_SEARCH_TIMEOUT
. - limit (int) – The maximum number of objects to return.
- deref_aliases (DerefAliases) – One of the
DerefAliases
constants. This instructs the server what to do when it encounters an alias object. The default can be set per connection by passing thederef_aliases
keyword to theLDAP
constructor, or set the global default by definingLDAP.DEFAULT_DEREF_ALIASES
. - attrs_only (bool) – Default False. Set to True to only obtain attribute names and not any attribute values.
- fetch_result_refs (bool) – When the server returns a result which is a reference to an object on another
server, automatically attempt to fetch the remote object and include it in the
iterated results. The default can be set per connection by passing the
fetch_result_refs
keyword to theLDAP
constructor, or set the global default by definingLDAP.DEFAULT_FETCH_RESULT_REFS
. - follow_referrals (bool) – When the server knows that the base object is present on another server, follow
the referral and perform the search on the other server. The default can be set
per connection by passing the follow_referrals keyword to the
LDAP
constructor, or set the global default by definingLDAP.DEFAULT_FOLLOW_REFERRALS
. - filter_syntax (FilterSyntax) – Select which filter syntax to use to parse the
filter
. The default can be set per connection by passing thedefault_filter_syntax
keyword to theLDAP
constructor, or set the global default by definingLDAP.DEFAULT_FILTER_SYNTAX
.
Returns: An iterator over the results of the search. May yield
LDAPObject
or possiblySearchReferenceHandle
iffetch_result_refs
is False.Additional keywords are handled as Controls first and then passed through into
LDAP.obj()
.This method may also be used as a context manager. If all results have not been read, the operation will automatically be abandoned when the context manager exits. You can also raise
Abandon
to abandon all results immediately and cleanly exit the context manager. You can also callSearchResultHandle.abandon()
to abandon results.Example:
# Dump the whole tree with LDAP() as ldap: with ldap.base.search() as search: for result in search: print(result.format_ldif())
-
send_extended_request
(oid, value=None, **kwds)[source]¶ Send an extended request, returns instance of
ExtendedResponseHandle
This is mainly meant to be called by other built-in methods and client extensions. Requires handling of raw pyasn1 protocol objects.
Parameters: Returns: An iterator yielding tuples of the form (
rfc4511.IntermediateResponse
,rfc4511.Controls
) or (rfc4511.ExtendedResponse
,rfc4511.Controls
).Return type: Raises: - LDAPSupportError – if the OID is not listed in the supportedExtension attribute of the root DSE
- TypeError – if the value parameter is not a valid type
Additional keyword arguments are handled as Controls and then passed through into the
ExtendedResponseHandle
constructor.
-
simple_bind
(username='', password='', **ctrl_kwds)[source]¶ Performs a simple bind operation
Leave arguments as their default (empty strings) to attempt an anonymous simple bind
Additional keywords are used as Controls.
Parameters: Returns: A response object
Return type: Raises: - ConnectionUnbound – if the connection has been unbound/closed
- ConnectionAlreadyBound – if the connection has already been bound
-
start_tls
(verify=None, ca_file=None, ca_path=None, ca_data=None)[source]¶ Perform the StartTLS extended operation. This will instruct the server to begin encrypting this socket connection with TLS/SSL.
Parameters: - verify (bool) – Set to False to disable verification of the remote certificate. You can set the default
per-connection by passing the ssl_verify keyword to the
LDAP
constructor, or set the global default by definingLDAP.DEFAULT_SSL_VERIFY
. - ca_file (str) – Path to PEM-formatted concatenated CA certficates file. You can set the default
per-connection by passing the ssl_ca_file keyword to the
LDAP
constructor, or set the global default by definingLDAP.DEFAULT_SSL_CA_FILE
. - ca_path (str) – Path to directory with CA certs under hashed file names. See
https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_load_verify_locations.html for more
information about the format of this directory. You can set the default per-connection by
passing the ssl_ca_path keyword to the
LDAP
constructor, or set the global default by definingLDAP.DEFAULT_SSL_CA_PATH
. - ca_data (str or bytes) – An ASCII string of one or more PEM-encoded certs or a bytes object containing DER-encoded
certificates. You can set the default per-connection by passing the ssl_ca_data keyword to the
LDAP
constructor, or set the global default by definingLDAP_DEFAULT_SSL_CA_DATA
.
Return type: - verify (bool) – Set to False to disable verification of the remote certificate. You can set the default
per-connection by passing the ssl_verify keyword to the
-
tag
(tag)[source]¶ Get a tagged object.
Parameters: tag (str) – The tag name to retrieve Returns: The object created with the given tag Return type: LDAPObject Raises: TagError – if the given tag is not defined
-
unbind
(force=False)[source]¶ Send an unbind request and close the socket.
Parameters: force (bool) – Unbind and close the socket even if other objects still hold a reference to it. Raises: ConnectionUnbound – if the connection has already been unbound
-
validate_modify
(dn, modlist, current=None)[source]¶ Run all configured validators for the given modify operation
Parameters: - dn (str) – The DN of the object being modified
- modlist (list[Mod]) – The sequence of changes to be performed
- current (LDAPObject) – The current known state of the object
Return type: Raises: LDAPValidationError – if any validator fails the operation
-
validate_object
(obj, write=True)[source]¶ Run all configured validators for the given object.
Parameters: - obj (LDAPObject) – The object to validate
- write (bool) – True if this is for a write operation (e.g. an add)
Return type: Raises: LDAPValidationError – if any validator fails the object
-
who_am_i
(**ctrl_kwds)[source]¶ Perform the “Who Am I?” extended operation. This will confirm the identity that the connection is bound to.
Returns: A string describing the bound identity. One common form is “dn:cn=foo,dc=example,dc=org” but this will vary by server configuration and bind type/parameters. Return type: str Additional keyword arguments are handled as Controls.
- server (str or LDAPSocket) – URI string to connect to or an
-
class
laurelin.ldap.
LDAPURI
(uri)[source]¶ Bases:
object
Represents a parsed LDAP URI as specified in RFC4516
Supported extensions:
- “StartTLS”
Variables: - scheme (str) – urlparse standard
- netloc (str) – urlparse standard
- host_uri (str) – scheme://netloc for use with LDAPSocket
- dn (str) – Distinguished name
- attrs (list[str]) – list
- scope (Scope) – one of the
Scope
constants - filter (str) – The filter string
- starttls (bool) – True if StartTLS was requested
-
DEFAULT_ATTRS
= ['*']¶
-
DEFAULT_FILTER
= '(objectClass=*)'¶
-
DEFAULT_SCOPE
= Scope.BASE¶
-
DEFAULT_STARTTLS
= False¶
-
search
(**kwds)[source]¶ Perform the search operation described by the parsed URI
First opens a new connection with connection reuse disabled, then performs the search, and unbinds the connection. Server must allow anonymous read.
Additional keyword arguments are passed through into
LDAP.search()
.
-
class
laurelin.ldap.
Scope
[source]¶ Bases:
object
Scope constants. These instruct the server how far to take a search, relative to the base object
-
BASE
= Scope.BASE¶ Only search the base object
-
ONE
= Scope.ONE¶ Search the base object and its immediate children
-
ONELEVEL
= Scope.ONE¶
-
SUB
= Scope.SUB¶ Search the base object and all of its dscendants
-
SUBTREE
= Scope.SUB¶
-
-
class
laurelin.ldap.
DerefAliases
[source]¶ Bases:
object
DerefAliases constants. These instruct the server when to automatically resolve an alias object, rather than return the alias object itself
-
ALWAYS
= DerefAliases.ALWAYS¶ dereferences both the search base object and results
-
BASE
= DerefAliases.BASE¶ dereferences the search base object, but not search results
-
NEVER
= DerefAliases.NEVER¶ always return the alias object
-
SEARCH
= DerefAliases.SEARCH¶ dereferences search results, but not the base object itself
-
-
class
laurelin.ldap.
FilterSyntax
[source]¶ Bases:
object
Filter syntax selection constants. Used to determine which filter syntax to use when parsing a search filter.
-
SIMPLE
= FilterSyntax.SIMPLE¶
-
STANDARD
= FilterSyntax.STANDARD¶
-
UNIFIED
= FilterSyntax.UNIFIED¶
-
-
class
laurelin.ldap.
Control
[source]¶ Bases:
object
Request controls are exposed by allowing an additional keyword argument on a set of methods. The prepare() method takes the value passed in as a keyword argument and returns an rfc4511.Control.
Response controls are returned by setting an additional attribute on whichever object is returned by the called method. The raw response controlValue is passed to the handle() method, and any appropriate value may be returned.
Leave the RESPONSE_OID and response_attr attributes as a False value if there is no response control specified.
-
REQUEST_OID
= ''¶ Request OID of the control
-
RESPONSE_OID
= ''¶ Response OID of the control (may be equal to REQUEST_OID; may be left empty)
-
handle
(ctrl_value)[source]¶ Accepts raw response ctrl_value and may return any useful value.
There is no need to call this base function when overriding.
Parameters: ctrl_value (str) – The string response control value received from the server. Returns: The string ctrl_value unchanged by default. May be overridden to return any relevant value/type/structure.
-
keyword
= ''¶ keyword argument name
-
method
= ()¶ name(s) of the method which this control is used with
-
prepare
(ctrl_value, criticality)[source]¶ Accepts string controlValue and returns an rfc4511.Control instance
When overriding this function, you must always call and return this base function.
Parameters: - ctrl_value (str or bytes) – The string request control value to send to the server
- criticality (bool) – True if the control has criticality. This is indicated by wrapping the keyword
argument in
critical
oroptional
, and by the default_criticality keyword passed to theLDAP
constructor, and global defaultLDAP.DEFAULT_CRITICALITY
.
Returns: The protocol-level control object ready for transmission to the server
Return type: rfc4511.Control
-
response_attr
= ''¶ Name of the attribute where return of handle() will be stored
-
-
class
laurelin.ldap.
optional
(value)[source]¶ Bases:
object
used to mark controls as not having criticality
-
exception
laurelin.ldap.
LDAPError
[source]¶ Bases:
Exception
Base class for all exceptions raised by laurelin
-
exception
laurelin.ldap.
NoSearchResults
[source]¶ Bases:
laurelin.ldap.exceptions.UnexpectedSearchResults
Got no search results when one or more was required
-
exception
laurelin.ldap.
Abandon
[source]¶ Bases:
Exception
Can be raised to cleanly exit a context manager and abandon unread results
-
laurelin.ldap.
add_extension
(modname)[source]¶ Import an extension and prepare it for binding under its internally-defined name to LDAP and/or LDAPObject depending which extension classes are defined. This is only needed for extensions not yet patched into AVAILABLE_EXTENSIONS.
Parameters: modname (str) – The string module name containing an extension, can be any importable module, e.g. “laurelin.extensions.netgroups” Return type: None
-
class
laurelin.ldap.
BaseLaurelinExtension
(modname=None)[source]¶ Bases:
laurelin.ldap.extensible.registration.LaurelinRegistrar
,laurelin.ldap.extensible.registration.LaurelinTransiter
Base class for basic extension class. Can house schema and controls definitions.
-
INSTANCE
= None¶
-
NAME
= '__undefined__'¶
-
-
class
laurelin.ldap.
BaseLaurelinSchema
[source]¶ Bases:
laurelin.ldap.extensible.registration.LaurelinTransiter
Optional base class for a class defining schema elements - only subclassing LaurelinTransiter is required
-
class
laurelin.ldap.
BaseLaurelinControls
[source]¶ Bases:
laurelin.ldap.extensible.registration.LaurelinTransiter
Optional base class for a class defining controls - only subclassing LaurelinTransiter is required
-
class
laurelin.ldap.
BaseLaurelinLDAPExtension
(parent)[source]¶ Bases:
object
Base class for extensions to the LDAP class
-
class
laurelin.ldap.
BaseLaurelinLDAPObjectExtension
(parent)[source]¶ Bases:
object
Base class for extensions to the LDAPObject class
-
class
laurelin.ldap.
LaurelinTransiter
[source]¶ Bases:
object
Base class for classes in extensions defining schema elements or controls
-
class
laurelin.ldap.
LaurelinRegistrar
(modname=None)[source]¶ Bases:
object
The require() method on this class registers all schema and controls in a module.
If this class is subclassed in an extension module (such as with LaurelinExtension), there is no need to pass an argument to the constructor. However, for extensions with many schema elements or controls, it may be desirable to break up these objects into multiple submodules that are imported on end-user request.
In such a setup, an instance of LaurelinRegistrar would need to be created and exposed to the end-user for each submodule so that they can call
.require()
on it. This constructor would need to be passed__name__
.Note that if this is applied to a package, require() will function on all imported submodules of the package.
-
laurelin.ldap.
escape
(text)¶ Escape special characters
-
class
laurelin.ldap.
LDAPObject
(dn, attrs_dict=None, ldap_conn=None, relative_search_scope=Scope.SUB, rdn_attr=None)[source]¶ Bases:
laurelin.ldap.attrsdict.AttrsDict
,laurelin.ldap.extensible.ldapobject_extensions.LDAPObjectExtensions
Represents a single object with optional server affinity.
Many methods will raise an exception if used without a server connection. To instantiate an
LDAPObject
bound to a server connection, useLDAP.obj()
.Attributes and values are stored using the mapping interface inherited from AttrsDict, where dict keys are case-insensitive attribute names, and dict values are a list of attribute values.
Value lists are automatically wrapped in
AttrValueList
. This allows the use of any schema-defined matching and syntax rules for the attribute type in list operations.Parameters: - dn (str) – The DN of the object
- attrs_dict (dict(str, list[str or bytes]) or AttrsDict or None) – The object’s attributes
- ldap_conn (LDAP or None) – The optional LDAP connection to use
- relative_search_scope (Scope) – One of the
Scope
constants, this is the default scope used when using this object’sLDAPObject.search()
method. New objects created below this one will inherit this attribute by default. This attribute also defines the behavior ofLDAPObject.find()
. - rdn_attr (str or None) – The default attribute name used in RDN’s for descendents of this object. If specified, this
allows you to only specify the value for methods that have an
rdn
argument. You can always specify a full attr=value forrdn
arguments as well to override this behavior. New objects created below this one will inherit this attribute by default.
-
add_attrs
(attrs_dict, **ctrl_kwds)[source]¶ Add new attribute values to this object.
Parameters: attrs_dict (dict(str, list[str or bytes]) or AttrsDict) – The new attributes to add to the object Return type: None Additional keywords are passed through into
LDAPObject.modify()
.
-
add_child
(rdn, attrs_dict, **kwds)[source]¶ Create a new object below this one.
Parameters: Returns: The new object
Return type: Additional keyword arguments are passed through into
LDAP.add()
-
compare
(attr, value)[source]¶ Ask the server if this object has a matching attribute value. The comparison will take place following the schema-defined matching rules and syntax rules.
Parameters: Returns: A response object,
bool()
evaluating to the result of the comparisonReturn type: Raises: RuntimeError – if this object is not bound to an LDAP connection
-
delete
(**ctrl_kwds)[source]¶ Delete the entire object from the server, and render this instance useless.
Additional keywords are passed through into
LDAP.delete()
.Return type: None Raises: RuntimeError – if this object is not bound to an LDAP connection
-
delete_attrs
(attrs_dict, **ctrl_kwds)[source]¶ Delete specifc attribute values given in
attrs_dict
. Specifying a zero-length list for any attribute will delete all values for that attribute.Parameters: attrs_dict (dict(str, list[str or bytes]) or AttrsDict) – The attributes to delete from the object Return type: None Additional keywords are passed through into
LDAPObject.modify()
.
-
delete_child
(rdn, **ctrl_kwds)[source]¶ Delete a child object below this one.
Parameters: rdn (str) – The RDN, or RDN value if rdn_attr is defined for this object Returns: The LDAPResponse
from the delete operationReturn type: LDAPResponse Additional keyword arguments are treated as controls.
-
find
(rdn, attrs=None, **kwds)[source]¶ Obtain a single object below this one with the most efficient means possible.
The strategy used is based on the
relative_search_scope
property of this object.- If it is
Scope.BASE
, this method will always raise anLDAPError
. - If it is
Scope.ONE
, then the absolute DN for the child object will be constructed, and aScope.BASE
search will be performed to get the object. - If it is
Scope.SUB
, then a subtree search will be performed below this object, using the RDN as a search filter.
Additional keywords are passed through into
LDAPObject.search()
.Parameters: Returns: The LDAP object
Return type: Raises: - LDAPError – if this object’s
relative_search_scope
isScope.BASE
. - NoSearchResults – if no object could be found matching
rdn
. - MultipleSearchResults – if more than one object was found.
- RuntimeError – if this object is not bound to an LDAP connection
- ValueError – if the
relative_search_scope
is set to an invalid value.
- If it is
-
format_ldif
()[source]¶ Format the object as an LDIF string.
Returns: The object encoded as an LDIF. Return type: str
-
get_child
(rdn, attrs=None, **kwds)[source]¶ Query the server for a child object.
Parameters: Returns: The object populated with data from the server
Return type: Raises: RuntimeError – if this object is not bound to an LDAP connection
Additional keywords are passed through into
LDAP.search()
andLDAPObject
-
has_object_class
(object_class)[source]¶ A convenience method which checks if this object has a particular objectClass. May query the server for the objectClass attribute if it is not yet known.
Parameters: object_class – The objectClass to check for. Returns: True if the objectClass is present, False otherwise Return type: bool
-
mod_dn
(new_rdn, clean_attr=True, new_parent=None, **ctrl_kwds)[source]¶ Change the object DN, and possibly its location in the tree.
Parameters: Return type: Raises: RuntimeError – if this object is not bound to an LDAP connection
Additional keywords are passed through into
LDAP.mod_dn()
.
-
mod_transaction
()[source]¶ Begin a modify transaction on this object. Important: This IS NOT an RFC 5805 transaction.
Return type: ModTransactionObject
-
modify
(modlist, **ctrl_kwds)[source]¶ Perform a series of modify operations on this object atomically.
Parameters: modlist (list[Mod]) – A list of Mod
instances, e.g. [Mod(Mod.ADD, ‘someAttr’, [‘value1’, ‘value2’])]Return type: None Raises: RuntimeError – if this object is not bound to an LDAP connection Additional keywords are passed through into
LDAP.modify()
.
-
move
(new_dn, clean_attr=True, **ctrl_kwds)[source]¶ Specify the complete new absolute DN for this object.
Parameters: Return type: Additional keywords are passed through into
LDAPObject.mod_dn()
.
-
obj
(rdn, attrs_dict=None, tag=None, **kwds)[source]¶ Create a new object below this one.
Parameters: Returns: The new object
Return type: Raises: LDAPError – if a
tag
is specified but this object is not bound to an LDAP connectionAdditional keywords are passed through into
LDAP.obj()
. or theLDAPObject
constructor.
-
rdn
(rdn)[source]¶ Return an absolute DN from an RDN or RDN value
Parameters: rdn (str) – The RDN, or RDN value if rdn_attr is defined for this object Returns: The absolute DN Return type: str
-
refresh
(attrs=None)[source]¶ Query the server to update the attributes on this object.
Parameters: attrs (list[str]) – Optional. A list of attribute names to query. If not specified, will query the server for all user attributes. Return type: None Raises: RuntimeError – if this object is not bound to an LDAP connection
-
refresh_all
()[source]¶ Query the server to update all user and operational attributes on this object.
Return type: None Raises: RuntimeError – if this object is not bound to an LDAP connection
-
refresh_missing
(attrs)[source]¶ Potentially query the server for any listed attributes that are not yet defined on this object. If no listed attributes aren’t defined, the query will not be performed. If a subset of the list is undefined, only those attributes will be queried.
Parameters: attrs (list[str]) – A list of attribute names to check, and possibly query for. Return type: None
-
rename
(new_rdn, clean_attr=True, **ctrl_kwds)[source]¶ Change the object’s RDN without changing it’s location in the tree.
Parameters: Return type: Additional keywords are passed through into
LDAPObject.mod_dn()
.
-
replace_attrs
(attrs_dict, **ctrl_kwds)[source]¶ Replace all values on the given attributes with the passed values.
Parameters: attrs_dict (dict(str, list[str or bytes]) or AttrsDict) – The new attributes to set on the object Return type: None Additional keywords are passed through into
LDAPObject.modify()
.
-
search
(filter=None, attrs=None, **kwds)[source]¶ Perform a search below this object.
Parameters: Returns: An iterator over
LDAPObject
and possiblySearchReferenceHandle
. SeeLDAP.search()
for more details.Return type: Additional keywords are passed through into
LDAP.search()
.
-
class
laurelin.ldap.
Mod
(op, attr, vals)[source]¶ Bases:
object
Describes a single modify operation
-
ADD
= Mod.ADD¶
-
DELETE
= Mod.DELETE¶
-
REPLACE
= Mod.REPLACE¶
-
static
op_to_string
(op)[source]¶ Convert one of the
Mod
constants to a string, e.g. “ADD”, “REPLACE”, “DELETE”.
-
static
string
(op)[source]¶ Translte LDIF changetype strings to constant. e.g. “replace” ->
Mod.REPLACE
-
-
laurelin.ldap.
get_object_class
(ident)[source]¶ Get an instance of
ObjectClass
associated with either a name or an OIDParameters: ident (str) – Either the numeric OID of the desired object class spec or one of its specified names Returns: The ObjectClass associated with the name/OID Return type: ObjectClass
-
class
laurelin.ldap.
ObjectClass
(spec)[source]¶ Bases:
object
Parses an LDAP object class specification and implements superclass inheritance.
Each instantiation registers the names and OID specified so that they can later be access with
get_object_class()
.See the
laurelin.ldap.schema
module source for example usages.Parameters: spec (str) – The LDAP specification for an object class
Raises: - if the schema is syntactically invalid
- if the OID specified has already been registered
- if one of the names specified has already been registered
Variables: - oid (str) – The specified OID
- names (tuple(str)) – All specified names
- superclasses (list[str]) – The list of all specified superclass names/OIDs.
- kind (str) – One of ABSTRACT, STRUCTURAL, or AUXILIARY
- obsolete (bool) – True if the objectClass has been marked obsolete.
- my_must (list[str]) – The list of required attribute types for this class
- my_may (list[str]) – The list of allowed attribute types for this class
-
allowed_attr
(name)[source]¶ Check if the given attribute type name is allowed.
Parameters: name – The name of the attribute type to check Returns: True if the given attribute type is allowed. Return type: bool
-
may
¶ Obtains all allowed attribute types after ascending the superclass specifications
-
must
¶ Obtains all required attribute types after ascending the superclass specifications
-
class
laurelin.ldap.
ExtensibleObjectClass
(spec)[source]¶ Bases:
laurelin.ldap.objectclass.ObjectClass
The extensibleObject auxiliary objectClass allows entries that belong to it to hold any user attribute.
-
class
laurelin.ldap.
SyntaxRule
[source]¶ Bases:
object
Base class for all syntax rules
-
DESC
= ''¶ Short text description of the rule. Must be defined by subclasses.
-
OID
= ''¶ The globally unique numeric OID of the syntax rule. Referenced in attribute type and matching rule specs. Must be defined by subclasses.
-
validate
(s)[source]¶ Validate a string. Must be implemented by subclasses.
Parameters: s – Candidate string Returns: Any useful value for the rule Raises: InvalidSyntaxError – if the string is invalid
-
-
class
laurelin.ldap.
RegexSyntaxRule
[source]¶ Bases:
laurelin.ldap.rules.SyntaxRule
For validating rules based on a regular expression. Most syntax rules can inherit from this.
-
regex
= ''¶ The regular expression defining the rule. Subclasses must define this attribute.
-
validate
(s)[source]¶ Validate a string against the regular expression.
Parameters: s – Candidate string Returns: The regex match object Return type: MatchObject Raises: InvalidSyntaxError – if the string does not match
-
-
class
laurelin.ldap.
MatchingRule
[source]¶ Bases:
object
Base class for all matching rules
-
NAME
= ''¶ Globally unique name for the matching rule. Most attribute type specs will reference rules using the name, but they can also use the OID. This must be defined by subclasses.
-
OID
= ''¶ Globally unique numeric OID for the matching rule. This must be defined by subclasses.
-
SYNTAX
= ''¶ The numeric OID for the syntax rule that assertion values must comply with. Subclasses must define this.
-
match
(attribute_value, assertion_value)[source]¶ Prepare values and perform the match operation. Assumes values have already been validated.
-
prep_methods
= ()¶ A tuple of callables used to prepare attribute and asserion values. Subclasses may optionally define this.
-
-
class
laurelin.ldap.
EqualityMatchingRule
[source]¶ Bases:
laurelin.ldap.rules.MatchingRule
Base class for all EQUALITY matching rules
-
class
laurelin.ldap.
Validator
[source]¶ Bases:
object
Abstract base class for a validator. All validators must inherit from here and ensure the public interface is fully implemented.
-
validate_modify
(dn, modlist, current)[source]¶ Validate a modify operation.
By default, validate all attributes for writing.
Parameters: - dn (str) – The DN of the object being modified
- modlist (list[Mod]) – The list of modify operations to be performed this transaction
- current (LDAPObject or None) – The known state of the object prior to modification
Returns: None
Raises: LDAPValidationError – if any modify operation is invalid
-
validate_object
(obj, write=True)[source]¶ Validate an object when all attributes are present.
By default, validate all attributes on the object.
Parameters: - obj (LDAPObject) – An LDAP object with all attributes defined
- write (bool) – True if we are validating a write operation to the database
Returns: None
Raises: LDAPValidationError – if the object is invalid in any way
-
-
class
laurelin.ldap.
SchemaValidator
[source]¶ Bases:
laurelin.ldap.validation.Validator
Ensures parameters conform to the available defined schema
-
validate_object
(obj, write=True)[source]¶ Validates an object when all attributes are present
- Requires the objectClass attribute
- Checks that all attributes required by the objectClass are defined
- Checks that all attributes are allowed by the objectClass
- Performs validation against the attribute type spec for all attributes
-
Module contents¶
Testing Setup¶
Warning
Testing has been moved to docker using public images. Check .travis.yml
for details. This page is maintained for
historical documentation purposes.
System¶
- Digital Ocean VPS with Debian 7.9
- OpenLDAP 2.4.31
- Cyrus SASL 2.1.25
- 389 Directory Server 1.3.6
SASL¶
SASL config ldif¶
dn: cn=config changetype: modify replace: olcAuthzRegexp olcAuthzRegexp: uid=([^,]+),.* cn=$1,dc=example,dc=org - add: olcSaslAuxprops olcSaslAuxprops: sasldb - add: olcSaslRealm olcSaslRealm: example.org - add: olcSaslHost olcSaslHost: example.org -
Adding sasl user password with¶
saslpasswd2 -u example.org -c $USER
SASL auth control test case¶
% ldapwhoami -Y DIGEST-MD5 -U admin -H ldap://127.0.0.1 SASL/DIGEST-MD5 authentication started Please enter your password: SASL username: admin SASL SSF: 128 SASL data security layer installed. dn:cn=admin,dc=example,dc=org
LDAPS/StartTLS¶
Certs set up following this Stack Overflow answer.
Configured OpenLDAP as follows:
dn: cn=config changetype: modify replace: olcTLSCertificateKeyFile olcTLSCertificateKeyFile: /certs/serverkey.pem - replace: olcTLSCertificateFile olcTLSCertificateFile: /certs/servercert.pem - replace: olcTLSCACertificateFile olcTLSCACertificateFile: /certs/cacert.pem
Added
ldaps://127.0.0.1:636
toSLAPD_SERVICES
in/etc/default/slapd