ldap3-orm module¶
This module provides classes for creating object-relational mappings for
LDAP data. In particular it provides the base class
EntryBase which uses class attributes in order to
configure the ORM model and dynamically creates a appropriate constructor
with the objective of writing less code and to focus on the configuration.
ORM Modelling¶
-
class
ldap3_orm.ParamDef(*args, **kwargs)[source]¶ Hold the definition of a parameter
This class provides a parameter definition which can be used in addition to attributes defined using
AttrDef. The parameter definition is used in the same way as forAttrDefexcept that it is not added the schema.
-
class
ldap3_orm.EntryBase(**kwargs)[source]¶ Base class for creating object-relational mapping ldap entries.
Configuring ORM models
A mapping can be configured using class attributes of type
AttrDef, e.g.:class User(EntryBase): ... username = AttrDef("uid")
The class attribute
usernamedescribes the ldap attributeuid. For each class attribute of typeAttrDefa corresponding keyword argument in the constructor will be generated to initialize this attribute. Thus theUserhas one ldap attribute nameduidwhich has to be set in the constructor e.g. usingusername="guest". Ldap attributes can be accessed either by sequence, by assignment or as dictionary keys. Keys are not case sensitive.Ldap attributes are declared mandatory in
AttrDefby default. This can be changed either providing a reasonable default value using thedefaultkeyword argument or settingmandatory=False.If the class attribute has the same name as the ldap attribute the latter will be resolved when accessing the attribute on an instance whereas the class attribute will be resolved when accessed on the class. Furthermore all class attributes of type
AttrDefwill be promoted toOperatorAttrDefin order to support filter expressions.For more information about ldap attribute access, inherited methods, etc. have a look at
Entry.For more information about filter expressions have a look at ORM Filter Expressions.
Validation of ldap attributes can be configured by passing validate = callable to
AttrDefwhere callable must accept the value which should be assigned to the attribute as argument. The callable must return a boolean allowing or denying the validation or raise an exception.Attributes
-
dn¶ distinguished name, an unique identifier in your ldap tree
Each subclass of this class must define this attribute.
This attribute can be defined as a template using python’s built-in
format()function. All class attributes and attributes configured viaAttrDefwill be expanded. Furthermore the generated DN will be normalized and escaped using theldap3.utils.dn.safe_dn()function.
-
object_classes¶ a set of object classes to which an entry of this class belongs, necessary for creating an new entry in the ldap tree.
Example:
validateuser = lambda value: value.isalpha() class User(EntryBase): dn = "uid={uid},{base_dn}" base_dn = "ou=People,dc=example,dc=com" username = AttrDef("uid", validate=validateuser) >>> User(username="guest") DN: uid=guest,ou=People,dc=example,dc=com uid: guest
The distinguished name
DNin this example has been initialized with the values of the configureduidldap attribute and the class attributebase_dn.The
usernamehas been validated usingvalidateuserwhich accepts only alphabetic characters. Thus the following code will raiseTypeError.>>> User(username="guest42") TypeError: Validation failed for attribute 'uid' and value 'guest42'
In order to support keyword arguments used as a template for the DN it is possible to define parameter definitions using
ParamDefin the same way asAttrDef, except that they are not added as ldap attributes.Example:
class Automount(EntryBase): dn = "cn={cn},ou={automap},{base_dn}" base_dn = "cn=automount,dc=example,dc=com" object_classes = ["top", "automount"] autofile = ParamDef("automap", default="auto.master") key = AttrDef("cn") info = AttrDef("automountInformation") >>> Automount(key="/Scratch", info="examplenfs.example.com:/Scratch", autofile="auto_nfs") DN: cn=/Scratch,ou=auto_nfs,cn=automount,dc=example,dc=com automountInformation: examplenfs.example.com:/Scratch cn: /Scratch
-
Automatic ORM Model Creation¶
-
ldap3_orm.EntryType(dn, object_classes, schema=None, *args, **kwargs)[source]¶ Factory for creating ORM models from given object classes.
Creating ORM models automatically
EntryType()dynamically creates new classes derived fromEntryBaseusing the following arguments:- dn – distinguished name, an unique identifier in your ldap tree
This attribute can be defined as a template using python’s built-in
format()function. All class attributes and dynamically generated attributes defined by givenschemaandobject_classeswill be expanded.
- object_classes – one or multiple object class(es) which should be
included in the generated model.
- schema –
ldap3_orm.Connection,ServerorSchemaInfowhich will be used to generate the model from the corresponding schema information.
Furthermore all arguments which can be passed either as a positional argument or as keyword argument to
ObjectDefcan be passed to thisEntryType().Example:
InetUser = EntryType("uid={uid},ou=People," + config.base_dn, "inetUser", conn) >>> u = InetUser(uid="guest", userPassword="{SSHA}oKJYPtoC+8mPBn/f47cSK5xWJuap183E") >>> InetUser OBJ : inetUser DN : uid={uid},ou=People,dc=example,dc=com MUST: MAY : inetUserHttpURL, inetUserStatus, memberOf, uid, userPassword >>> u DN: uid=guest,ou=People,dc=example,dc=com objectClass: inetUser uid: guest userPassword: {SSHA}oKJYPtoC+8mPBn/f47cSK5xWJuap183E
ORM Filter Expressions¶
ldap3-orm supports querying LDAP directories without any knowledge about the LDAP filter syntax defined in RFC 4515 simply using ORM models and Python operators. Nevertheless the usual LDAP filter syntax as well as the Simplified Query Language defined in the ldap3 project and ORM Filter Expressions can be used vice versa.
Note
ldap3-orm filter expressions can be used on ldap3_orm.Connection and ldap3_orm.Reader objects. Please ensure that you are importing
those classes from the ldap3_orm module and not from
ldap3. Both classes inherit from its originating ones and have
just been extended to support ORM Filter Expressions.
Assuming we have created the following ORM model for a LDAP user entry:
from ldap3_orm import EntryBase, AttrDef
class User(EntryBase):
dn = "uid={uid},{base_dn}"
base_dn = "ou=People,dc=example,dc=com"
object_classes = ["top", "inetUser", "inetOrgPerson"]
username = AttrDef("uid")
password = AttrDef("userPassword")
fullname = AttrDef("cn")
givenname = AttrDef("givenName")
surname = AttrDef("sn")
email = AttrDef("mail")
and we have created an active ldap3_orm.Connection object:
>>> from ldap3_orm import ALL_ATTRIBUTES, Connection, ObjectDef, Reader
>>> with Connection("ldap://ldap.example.com", "cn=directory manager",
"secret", auto_bind=True) as conn:
We can query for an user entry using his unique username.
>>> search_base = "ou=People,dc=example,dc=com"
>>> conn.search(search_base, User.username == "guest",
attributes=ALL_ATTRIBUTES)
True
>>> conn.entries
[DN: uid=guest,ou=People,dc=example,dc=com - STATUS: Read - READ TIME:
2018-03-15T14:32:00.369434
cn: Guest User
givenName: Guest
mail: guest.user@example.com
sn: User
uid: guest
userPassword: {SSHA}oKJYPtoC+8mPBn/f47cSK5xWJuap183E
]
We can have a look at the internaly generated LDAP filter.
>>> User.username == "guest"
uid - mandatory: False - filter: (uid=jcnsgast)
>>> print(User.username == "guest")
'(uid=guest)'
We can use ldap3_orm.Reader objects.
>>> r = Reader(conn, ObjectDef("inetOrgPerson", conn), search_base,
User.username == "guest")
>>> r.query_filter
'(&(objectClass=inetOrgPerson)(uid=guest))'
>>> r.query
(uid=guest)
>>> r.search()
[DN: uid=guest,ou=People,dc=example,dc=com - STATUS: Read - READ TIME:
2018-03-15T14:32:00.369434
>>> r[0]
DN: uid=guest,ou=People,dc=example,dc=com - STATUS: Read - READ TIME:
2018-03-15T14:32:00.369434
Instead of creating our own models we can dynamically create a model from
our active connection using either
ldap3_orm.ObjectDef
>>> odef = ObjectDef("inetUser", conn)
>>> odef
OBJ : inetUser
AUX : <None>
OID: inetUser (Auxiliary) 2.16.840.1.113730.3.2.130, top (Abstract) 2.5.6.0
MUST: objectClass
MAY : inetUserHttpURL, inetUserStatus, memberOf, uid, userPassword
>>> print(odef.uid == "guest")
'(uid=guest)'
or a class generated from the EntryType factory.
>>> InetUser = EntryType("uid={uid},ou=People," + config.base_dn,
"inetUser", conn)
>>> print(InetUser.uid == "guest")
'(uid=guest)'
Operators¶
The following examples show some of ldap3-orm’s ORM Filter Expression capabilities. We have already seen that we can equate attributes:
>>> print(User.username == "guest")
'(uid=guest)'
ORM Filter Expressions are escaped:
>>> print(User.givenname == "Gu*")
(givenName=Gu\2a)
In order to get all users with its givenname starting with Gu use the
startswith operator:
>>> print(User.givenname.startswith("Gu"))
(givenName=Gu*)
For checking endings use the following:
>>> print(User.givenname.endswith("st"))
(givenName=*st)
Expressions can be combined using and &, or | operators:
>>> print(User.givenname.startswith("Chris")
... & ((User.surname == "Schmitz") | (User.surname == "Maier")))
(&(givenName=Chris*)(|(sn=Schmitz)(sn=Maier)))