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 forAttrDef
except 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
username
describes the ldap attributeuid
. For each class attribute of typeAttrDef
a corresponding keyword argument in the constructor will be generated to initialize this attribute. Thus theUser
has one ldap attribute nameduid
which 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
AttrDef
by default. This can be changed either providing a reasonable default value using thedefault
keyword 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
AttrDef
will be promoted toOperatorAttrDef
in 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
AttrDef
where 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 viaAttrDef
will 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
DN
in this example has been initialized with the values of the configureduid
ldap attribute and the class attributebase_dn
.The
username
has been validated usingvalidateuser
which 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
ParamDef
in 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 fromEntryBase
using 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 givenschema
andobject_classes
will be expanded.
- object_classes – one or multiple object class(es) which should be
included in the generated model.
- schema –
ldap3_orm.Connection
,Server
orSchemaInfo
which 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
ObjectDef
can 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)))