Welcome to Ldaptor’s documentation!¶
What is Ldaptor¶
Ldaptor is a pure-Python Twisted library that implements:
- LDAP client and server logic
- separately-accessible LDAP and BER protocol message generation/parsing
- ASCII-format LDAP filter generation and parsing
- LDIF format data generation
Get it from PyPI, find out what’s new in the Changelog!
Quick Start¶
LDAP Client Quickstart¶
from __future__ import print_function
from twisted.internet import reactor, defer
from twisted.internet.endpoints import clientFromString, connectProtocol
from twisted.internet.task import react
from ldaptor.protocols.ldap.ldapclient import LDAPClient
from ldaptor.protocols.ldap.ldapsyntax import LDAPEntry
import sys
@defer.inlineCallbacks
def onConnect(client):
basedn = 'dc=example,dc=org'
binddn = 'cn=bob,ou=people,dc=example,dc=org'
bindpw = 'secret'
query = '(cn=bob)'
try:
yield client.bind(binddn, bindpw)
except Exception as ex:
print(ex)
raise
o = LDAPEntry(client, basedn)
results = yield o.search(filterText=query)
for entry in results:
print(entry)
def onError(err):
err.printDetailedTraceback(file=sys.stderr)
def main(reactor):
endpoint_str = "tcp:host=127.0.0.1:port=8080"
e = clientFromString(reactor, endpoint_str)
d = connectProtocol(e, LDAPClient())
d.addCallback(onConnect)
d.addErrback(onError)
return d
react(main)
LDAP Server Quick Start¶
from twisted.application import service, internet
from twisted.internet.endpoints import serverFromString
from twisted.internet.protocol import ServerFactory
from twisted.python.components import registerAdapter
from twisted.python import log
from ldaptor.inmemory import fromLDIFFile
from ldaptor.interfaces import IConnectedLDAPEntry
from ldaptor.protocols.ldap import distinguishedname
from ldaptor.protocols.ldap.ldapserver import LDAPServer
import tempfile
from cStringIO import StringIO
import sys
LDIF = """\
dn: dc=org
dc: org
objectClass: dcObject
dn: dc=example,dc=org
dc: example
objectClass: dcObject
objectClass: organization
dn: ou=people,dc=example,dc=org
objectClass: organizationalUnit
ou: people
dn: cn=bob,ou=people,dc=example,dc=org
cn: bob
gn: Bob
mail: bob@example.org
objectclass: top
objectclass: person
objectClass: inetOrgPerson
sn: Roberts
userPassword: secret
dn: gn=John+sn=Doe,ou=people,dc=example,dc=org
objectClass: addressbookPerson
gn: John
sn: Doe
street: Back alley
postOfficeBox: 123
postalCode: 54321
postalAddress: Backstreet
st: NY
l: New York City
c: US
userPassword: terces
dn: gn=John+sn=Smith,ou=people, dc=example,dc=org
objectClass: addressbookPerson
gn: John
sn: Smith
telephoneNumber: 555-1234
facsimileTelephoneNumber: 555-1235
description: This is a description that can span multi
ple lines as long as the non-first lines are inden
ted in the LDIF.
userPassword: eekretsay
"""
class Tree(object):
def __init__(self):
global LDIF
self.f = StringIO(LDIF)
d = fromLDIFFile(self.f)
d.addCallback(self.ldifRead)
def ldifRead(self, result):
self.f.close()
self.db = result
class LDAPServerFactory(ServerFactory):
protocol = LDAPServer
def __init__(self, root):
self.root = root
def buildProtocol(self, addr):
proto = self.protocol()
proto.debug = self.debug
proto.factory = self
return proto
if __name__ == '__main__':
from twisted.internet import reactor
if len(sys.argv) == 2:
port = int(sys.argv[1])
else:
port = 8080
# First of all, to show logging info in stdout :
log.startLogging(sys.stderr)
# We initialize our tree
tree = Tree()
# When the LDAP Server protocol wants to manipulate the DIT, it invokes
# `root = interfaces.IConnectedLDAPEntry(self.factory)` to get the root
# of the DIT. The factory that creates the protocol must therefore
# be adapted to the IConnectedLDAPEntry interface.
registerAdapter(
lambda x: x.root,
LDAPServerFactory,
IConnectedLDAPEntry)
factory = LDAPServerFactory(tree.db)
factory.debug = True
application = service.Application("ldaptor-server")
myService = service.IServiceCollection(application)
serverEndpointStr = "tcp:{0}".format(port)
e = serverFromString(reactor, serverEndpointStr)
d = e.listen(factory)
reactor.run()
User’s Guide¶
Introduction to LDAP¶
Foreword¶
This text is intended as a quick introduction to the interesting bits of the LDAP protocol, and should be useful whether you are managing an LDAP server, programming something using an LDAP library, or writing an LDAP library yourself. I welcome any feedback you might have.
LDAP Presents a Distributed Tree of Information¶
Probably the nicest way to get a mental model of LDAP information is to think of a tree with elements both in leaf and non-leaf nodes. Parts of the tree may reside at different LDAP servers.

An organization normally uses their DNS domain name as the root entry for their local LDAP tree.
For example, example.com
is free to use dc=example,dc=com
.
The dc
stands for domainComponent
.
An alternative is to identify the organization via geographical location, as in o=Example Inc., c=US
, but this is cumbersome as it requires registration to avoid name conflicts.
The o
stands for organization, c
for country.
You will also encounter ou
, short for organizational unit.
Each node of the tree is called an “LDAP entry”, and can contain multiple attributes in the form of attributeType=value pairs, for example surname=Wiesel
.
One attributeType may appear multiple times, in effect having multiple values.
One or more of the attributes are chosen as a Relative Distinguished Name or RDN, and will be used to identify the node based on its parent. This means the RDN must be unique among the children of its parent. Listing all the RDNs, separated by commas, from the node to the root, gives us the Distinguished Name or DN of the entry.
- The RDN of the entry for Jack E. Wiesel is
cn=Jack E. Wiesel
. - The DN is
cn=Jack E. Wiesel,ou=Sales,ou=People,dc=example,dc=com
. - The
cn
is short for common name.
The RDN of the entry for John Doe consist of two attributes, gn=John
and sn=Doe
, joined with a plus sign to form gn=John+sn=Doe
.
gn
is short for given name (first name), sn
for surname (last name).
Objectclasses and Schemas¶
A special attributeType of objectClass
lists all the objectclasses the LDAP entry manifests.
An object class basically lists what attribute types an entry must have, and what optional attribute types it may have.
For example, telephone directory entries must have a name and a telephone number, and may have a fax number and street address.
objectClass
can have multiple values, allowing the same entry to describe e.g. information about a person both for a telephone directory and for UNIX shell login.
An LDAP schema is a part of the configuration of the LDAP server, containing two things: definitions of attribute types and definitions of objectclasses. It is normally stored as ASCII text, but can e.g. be requested from the server over an LDAP connection.
An attribute type definition commonly contains a global identifier for the attribute type (a list of period-separated integers), a list of names for the attribute type, a free-form description and a reference to another attribute type this definition inherits from. It may also contain information about what sort of data the attribute values may contain, how to compare and sort them, how to find substrings in the value, whether the attribute type can have multiple values, etc.
An example attributeType definition:
attributetype ( 2.5.4.4 NAME ( 'sn' 'surname' )
DESC 'RFC2256: last (family) name(s) for which the entity is known by'
SUP name )
An object class definition also commonly contains a global identifier, name, description and inheritance information.
It also commonly lists the attribute types entries having this object class must have, and additional attribute types they may have.
An entry cannot have attribute types that are not listed as a MUST
or MAY
by one of the entrys object classes or their parents.
An example objectClass definition:
objectclass ( 2.5.6.6 NAME 'person' DESC 'RFC2256: a person'
SUP top STRUCTURAL MUST ( sn $ cn ) MAY
( userPassword $ telephoneNumber $ seeAlso $ description ) )
There are a lot of pre-existing schemas, standardized in various RFCs. Also, anyone can create their own schemas. The only things you need are access to the LDAP server configuration, and a number reserved for you, which can be achieved by filling a web form.
Object-oriented look at LDAP entries¶
If you look at LDAP entries from the viewpoint of a programmer accustomed with object oriented programming, you will see a lot of similarities, but also some striking differences.
Writing Things Down: LDIF¶
There is a standardized way of writing down, in plain text, the contents of LDAP directories, individual entries and even add, delete and modify operations. This format is known as LDIF (LDAP Data Interchange Format) LDAP Data Interchange Format, and it is defined in RFC2849.
The rough format of LDIF is this: there is a paragraph per entry, where paragraphs are separated by blank lines.
Each paragraph contains lines in the format keyword:value.
Entries start by listing the keyword dn
, and their DN, and then list all the attributes and values the entry has.
Lines starting with space are appended to the previous line.
The whole file starts with the keyword version and value 1.
Note
The actual format is more complex, but this tutorial should allow you to read and write normal LDIF files fluently.
A simple LDAP file with two entries:
version: 1
dn: cn=Barbara Jensen, ou=Product Development, dc=airius, dc=com
objectclass: top
objectclass: person
objectclass: organizationalPerson
cn: Barbara Jensen
cn: Barbara J Jensen
cn: Babs Jensen
sn: Jensen
uid: bjensen
telephonenumber: +1 408 555 1212
description: A big sailing fan.
dn: cn=Bjorn Jensen, ou=Accounting, dc=airius, dc=com
objectclass: top
objectclass: person
objectclass: organizationalPerson
cn: Bjorn Jensen
sn: Jensen
telephonenumber: +1 408 555 1212
A file containing an entry with a folded attribute value, from RFC 2849:
version: 1
dn:cn=Barbara Jensen, ou=Product Development, dc=airius, dc=com
objectclass:top
objectclass:person
objectclass:organizationalPerson
cn:Barbara Jensen
cn:Barbara J Jensen
cn:Babs Jensen
sn:Jensen
uid:bjensen
telephonenumber:+1 408 555 1212
description:Babs is a big sailing fan, and travels extensively in search of perfect sailing conditions.
title:Product Manager, Rod and Reel Division
Searches and Search Filters¶
The most common LDAP operation is a search, and LDAP is purposefully designed for environments where searches are many times more common than modify operations. In general, LDAP servers index the entries and can effectively search for matches against a reasonably complex criteria among thousands of entries.
An LDAP search takes the following information as input:
- base DN
- scope (base, one level, subtree)
- filter
- attributes requested
Note
Once again, we are skipping some details for understandability.
Of these, the search filter is clearly the most interesting one. As with LDIF, search filters have a standardized plain text representation, even though they are not transmitted as plain text in the actual protocol.
A search filter is basically a combination of tests an entry must fulfill in order to match the filter. They are always written inside parentheses. A simple example would be
(cn=John Smith)
but the filters can also match against presence, prefix, suffix, substring, rough equality, etc.
Multiple matches can be combined freely with and, or and not operators, which are represented by &
, |
and !
, respectively.
For example, to match only objects that have objectClass person
, where the full name contains the letters a and b in either order, and who don’t have a telephone number listed, we could use the filter
Note
Yes, once again we are skipping details for understandability. See RFC2254 for more.
(&(objectClass=person)(!(telephoneNumber=*))(|(cn=*a*b*)(cn=*b*a*)))

Phases of an LDAP Protocol Chat¶
An average LDAP protocol chat consists of three stages:
- Opening the connection
- Doing one or more searches
- Closing the connection
At the first stage, opening a connection, an LDAP client opens a TCP connection to the LDAP server, either as plain text, encrypted by TLS or starting with plaintext and switching to use TLS with STARTTLS.
The client authenticates itself and/or the user, providing any necessary authentication information. This is called binding. Normally, the connection is not really authenticated, but left as anonymous; the bind message is sent with no user or password information.

Next, the client sends a search request, containing the base DN for the search, the filter that entries must fulfill to match, and some extra settings discussed above.
The server replies by sending search result entries back, one message per matching entry. If no entry matched or there was an error before the search could even start, the server might not send any entries. Finally, the server sends a message indicating the search is done, and includes information on whether the search was completely successfully, or the error encountered.

Note that the client could have sent another search request without waiting for the first search to complete. The order of results from the different search, or when they are completed, is in no way guaranteed.

One important detail we have skimmed over so far is how the LDAP client knows what message the server is replying to. Earlier we avoided this topic just by doing only one thing at a time, but now we have two searches getting their result entries interleaved. Clearly, there must be a mechanism to separate which entries belong to which search request. And exactly such a mechanism exists; each message sent by the client contains a number identifying the request, and the server replies by including the same number in the reply. Now, all the client needs to do is remember which numbers are still in use, and not reuse those. It can internally maintain search state based on these numbers, and process result entries based on them. The client can reuse a number when it is known that no more server replies will be sent using that number; for example, the search done message gives this guarantee.
Finally, when the client no longer wants to talk to the server, it sends a message effectively saying
“good bye”. This message is known as unbind
.
This only means that the state of connection is the same as when connected, before the first bind
; that is, it un-authenticates the current user.
If the client really wants to close the connection, it will then close the TCP socket.

Please understand that these were just examples, and in reality protocol chats are often more complicated. For example, one could connect some other protocol servers, say a web servers, authentication mechanism to actually act as an LDAP client, that tries to bind as the user authenticating himself to the web server, with the password given by the user. If this service had no other interest in the contents of LDAP, it would probably immediately after the bind close the connection. But opening and closing TCP connections repeatedly is slow; it is quite likely the authentication mechanism would be changed to keep a single TCP connection alive, and just do repeated binds over the same connection.
Creating a Simple LDAP Application¶
An LDAP Primer¶
Entries in an LDAP directory information tree (DIT) are arranged in a hierarchy.

LDIF is a textual representation of entries in the DIT.
Writing things down, John Doe LDIF:
dn: gn=John+sn=Doe,ou=Research & Development,ou=People,dc=example,dc=com
objectClass: addressbookPerson
gn: John
sn: Doe
street: Back alley
postOfficeBox: 123
postalCode: 54321
postalAddress: Backstreet
st: NY
l: New York City
c: US
Writing things down, John Smith LDIF:
dn: gn=John+sn=Smith,ou=Marketing,ou=People, dc=example,dc=com
objectClass: addressbookPerson
gn: John
sn: Smith
telephoneNumber: 555-1234
facsimileTelephoneNumber: 555-1235
description: This is a description that can span multi
ple lines as long as the non-first lines are inden
ted in the LDIF.
Twisted¶
Twisted is an event-driven networking framework written in Python and licensed under the MIT (Expat) License.
Twisted supports TCP, UDP, SSL/TLS, multicast, Unix sockets, a large number of protocols (including HTTP, NNTP, SSH, IRC, FTP, and others), and much more.
Twisted includes many full-blown applications, such as web, SSH, FTP, DNS and news servers.
Deferreds¶
- A promise that a function will at some point have a result.
- You can attach callback functions to a Deferred.
- Once it gets a result these callbacks will be called.
- Also allows you to register a callback for an error, with the default behavior of logging the error.
- Standard way to handle all sorts of blocking or delayed operations.
Overview of Ldaptor¶

Asynchronous LDAP Clients and Servers¶
Ldaptor is a set of pure-Python LDAP client and server protocols and libraries..
It is licensed under the MIT (Expat) License.
Following Along with the Examples¶
If you are following along with the interactive examples, you will need an LDAP directory server to which the example client can connect. A script that creates such a client is available in the section LDAP Server Quick Start. Copy the script to a file quickstart_server.py and run it in another terminal:
$ python quickstart_server.py 10389
Note
Because of the asynchronous nature of Deferreds, a standard interactive Python shell won’t work treat the following examples the way you might expect. That is because the Twisted reator is not running, so connections will never be made and Deferreds will never fire their callback function(s).
If you want to follow along interactively, you can use the following interactive shell that comes with Twisted. It runs a reactor in the background so you can see deferred results:
$ python -m twisted.conch.stdio
Working with Distinguished Names¶
>>> from ldaptor.protocols.ldap import distinguishedname
>>> dn=distinguishedname.DistinguishedName(
... 'dc=example,dc=com')
>>> dn
DistinguishedName(listOfRDNs=(RelativeDistinguishedName(
attributeTypesAndValues=(LDAPAttributeTypeAndValue(
attributeType='dc', value='example'),)),
RelativeDistinguishedName(attributeTypesAndValues=(
LDAPAttributeTypeAndValue(attributeType='dc', value='com'),))))
>>> str(dn)
'dc=example,dc=com'
Connect to a Directory Asynchronously¶
Ldaptor contains helper classes to simplify connecting to an LDAP DIT.
>>> from ldaptor.protocols.ldap.ldapclient import LDAPClient
>>> from twisted.internet import reactor
>>> from twisted.internet.endpoints import clientFromString, connectProtocol
>>> e = clientFromString(reactor, "tcp:host=localhost:port=10389")
>>> e
<twisted.internet.endpoints.TCP4ClientEndpoint at 0xb452e0c>
>>> d = connectProtocol(e, LDAPClient())
>>> d
<Deferred at 0x36755a8 current result: <ldaptor.protocols.ldap.ldapclient.LDAPClient instance at 0x36757a0>>
Searching¶
Once connected to the DIT, an LDAP client can search for entries.
>>> proto = d.result
>>> proto
<ldaptor.protocols.ldap.ldapclient.LDAPClient instance at 0x40619dac>
>>> from ldaptor.protocols.ldap import ldapsyntax
>>> from ldaptor.protocols.ldap import distinguishedname
>>> dn = distinguishedname.DistinguishedName("dc=example,dc=org")
>>> baseEntry = ldapsyntax.LDAPEntry(client=proto, dn=dn)
>>> d2 = baseEntry.search(filterText='(gn=j*)')
>>> results = d2.result
Results¶
Search results are a list of LDAP entries.
>>> results
[LDAPEntry(dn='gn=John+sn=Smith,ou=People,
dc=example,dc=com', attributes={'description': ['Some text.'],
'facsimileTelephoneNumber': ['555-1235'], 'gn': ['John'],
'objectClass': ['addressbookPerson'], 'sn': ['Smith'],
'telephoneNumber': ['555-1234']}), LDAPEntry(dn=
'gn=John+sn=Doe,ou=People,dc=example,dc=com',
attributes={'c': ['US'], 'givenName': ['John'], 'l': ['New York City'],
'objectClass': ['addressbookPerson'], 'postOfficeBox': ['123'],
'postalAddress': ['Backstreet'], 'postalCode': ['54321'],
'sn': ['Doe'], 'st': ['NY'], 'street': ['Back alley']})]
Results one-by-one¶
You can inspect individual results in the result list.
>>> results[0]
LDAPEntry(dn=
'gn=John+sn=Smith,ou=People,dc=example,dc=com',
attributes={'description': ['Some text.'],
'facsimileTelephoneNumber': ['555-1235'], 'gn': ['John'],
'objectClass': ['addressbookPerson'], 'sn': ['Smith'],
'telephoneNumber': ['555-1234']})
>>> results[3]
Traceback (most recent call last):
File "<stdin>", line 1, in ?
IndexError: list index out of range
LDIF output¶
Search results can be printed as LDIF output. LDIF output can be used by other LDAP tools.
>>> print(results[0])
dn: gn=John+sn=Smith,ou=People,dc=example,dc=com
objectClass: addressbookPerson
description: Some text.
facsimileTelephoneNumber: 555-1235
gn: John
sn: Smith
telephoneNumber: 555-1234
Closing the connection¶
Unlike an HTTP connection, an LDAP connection persists until the client indicates it is done or the server forcibly terminates the connection (e.g. a TCP socket times out).
>>> proto.unbind()
Access to entry details¶
LDAP entries have a dictionary-like interface. Attributes are accessed like dictionary keys. The values are always a list of one or more values.
>>> smith = results[0]
>>> print(smith.dn)
gn=John+sn=Smith,ou=People,dc=example,dc=com
>>> smith['gn']
['John']
>>>
Anatomy of an LDAP entry¶
LDAP entries can “implement” multiple objectClasses.
All objectClasses can inherit zero, one or many objectClasses, just like programming classes.
All objectClasses have a root class, known as top; many object oriented programming languages have a root class, e.g. named Object.
All objectClasses are either STRUCTURAL or AUXILIARY; entries can only implement one STRUCTURAL objectClass.
Lastly, objectClasses of an entry can be changed at will; you only need to take care that the entry has all the MUST attribute types, and no attribute types outside of the ones that are MUST or MAY.
Note
Note that e.g. OpenLDAP doesn’t implement this.
Attributes of an entry closely match attributes of objects in programming languages; however, LDAP attributes may have multiple values.
Search inputs¶
An example search filter: (cn=John Smith)
A search filter, specifying criteria an entry must fulfill to match.
Scope of the search, either look at the base DN only, only look one level below it, or look at the whole subtree rooted at the base DN.
Size limit of at most how many matching entries to return.
Attributes to return, or none for all attributes the matching entries happen to have.
Our first Python program¶
#!/usr/bin/python
from twisted.internet import defer
from twisted.internet.task import react
from twisted.internet.endpoints import clientFromString, connectProtocol
from ldaptor import ldapfilter
from ldaptor.protocols.ldap import ldapsyntax
from ldaptor.protocols.ldap.ldapclient import LDAPClient
from ldaptor.protocols.ldap.distinguishedname import DistinguishedName
def search(reactor, endpointStr, base_dn):
e = clientFromString(reactor, endpointStr)
d = connectToLDAPEndpoint(e, LDAPClient())
def _doSearch(proto):
searchFilter = ldapfilter.parseFilter('(gn=j*)')
baseEntry = ldapsyntax.LDAPEntry(client=proto, dn=base_dn)
d = baseEntry.search(filterObject=searchFilter)
return d
d.addCallback(_doSearch)
return d
def main(reactor):
import sys
from twisted.python import log
log.startLogging(sys.stderr, setStdout=0)
dn = DistinguishedName('dc=example,dc=org')
d = search(reactor, 'tcp:host=localhost:port=10389', dn)
def _show(results):
for item in results:
print(item)
d.addCallback(_show)
d.addErrback(defer.logError)
d.addBoth(lambda _: reactor.stop())
return d
if __name__ == '__main__':
react(main)
Phases of the protocol chat¶
- Open and bind
- Search (possibly many times)
- Unbind and close
Opening and binding¶

Doing a search¶

Doing multiple searches¶

Unbinding and closing¶

A complex search filter¶
An example:
(&(objectClass=person)
(!(telephoneNumber=*))
(|(cn=*a*b*)(cn=*b*a*)))

Object classes¶
Special attribute
objectClass
lists all the objectclasses an LDAP entry manifests.- Objectclass defines
- What attributetypes an entry MUST have
- What attributetypes an entry MAY have
An entry in a phonebook must have a name and a telephone number, and may have a fax number and street address.
Schema¶
- A configuration file included in the LDAP server configuration.
- A combination of attribute type and object class definitions.
- Stored as plain text
- Can be requested over an LDAP connection
Attribute type¶
An example:
attributetype ( 2.5.4.4 NAME ( 'sn' 'surname' )
DESC 'RFC2256: last (family) name(s) for which the entity is known by'
SUP name )
Can also contain:
- content data type
- comparison and sort mechanism
- substring search mechanism
- whether multiple values are allowed
Object class¶
An example:
objectclass ( 2.5.6.6 NAME 'person'
DESC 'RFC2256: a person'
SUP top STRUCTURAL
MUST ( sn $ cn )
MAY ( userPassword $ telephoneNumber
$ seeAlso $ description )
)
Creating schemas¶
- Anyone can create their own schema
- Need to be globally unique
- But try to use already existing ones
Where to go from here?¶
Install OpenLDAP: http://www.openldap.org/
Install Ldaptor: https://github.com/twisted/ldaptor
Learn Python: http://www.python.org/
Learn Twisted. Write a client application for a simple protocol. Read the HOWTOs: http://twistedmatrix.com/documents/current/core/howto/clients.html
ldaptor API Reference¶
Subpackages¶
ldaptor.protocols package¶
LDAP object field value suggestion and autoupdate mechanism.
-
exception
ldaptor.protocols.ldap.autofill.
ObjectMissingObjectClassException
[source]¶ Bases:
ldaptor.protocols.ldap.autofill.AutofillException
The LDAPEntry is missing an objectClass this autofiller needs to operate.
-
class
ldaptor.protocols.ldap.distinguishedname.
DistinguishedName
(magic=None, stringValue=None, listOfRDNs=None)[source]¶ LDAP Distinguished Name.
-
listOfRDNs
= None¶
-
-
exception
ldaptor.protocols.ldap.distinguishedname.
InvalidRelativeDistinguishedName
(rdn)[source]¶ Bases:
exceptions.Exception
Invalid relative distinguished name.
-
class
ldaptor.protocols.ldap.distinguishedname.
LDAPAttributeTypeAndValue
(stringValue=None, attributeType=None, value=None)[source]¶ -
attributeType
= None¶
-
value
= None¶
-
LDAP protocol client
-
class
ldaptor.protocols.ldap.ldapclient.
LDAPClient
[source]¶ Bases:
twisted.internet.protocol.Protocol
An LDAP client
-
berdecoder
= <LDAPBERDecoderContext_TopLevel identities={0x10: LDAPMessage} fallback=None inherit=<LDAPBERDecoderContext_LDAPMessage identities={0x80: LDAPControls, 0x53: LDAPSearchResultReference} fallback=<LDAPBERDecoderContext identities={0x40: LDAPBindRequest, 0x41: LDAPBindResponse, 0x42: LDAPUnbindRequest, 0x43: LDAPSearchRequest, 0x44: LDAPSearchResultEntry, 0x45: LDAPSearchResultDone, 0x46: LDAPModifyRequest, 0x47: LDAPModifyResponse, 0x48: LDAPAddRequest, 0x49: LDAPAddResponse, 0x4a: LDAPDelRequest, 0x4b: LDAPDelResponse, 0x4c: LDAPModifyDNRequest, 0x4d: LDAPModifyDNResponse, 0x50: LDAPAbandonRequest, 0x83: LDAPReferral, 0x57: LDAPExtendedRequest, 0x58: LDAPExtendedResponse} fallback=<BERDecoderContext identities={0x01: BERBoolean, 0x02: BERInteger, 0x04: BEROctetString, 0x05: BERNull, 0x0a: BEREnumerated, 0x10: BERSequence, 0x11: BERSet} fallback=None inherit=None> inherit=None> inherit=<LDAPBERDecoderContext identities={0x40: LDAPBindRequest, 0x41: LDAPBindResponse, 0x42: LDAPUnbindRequest, 0x43: LDAPSearchRequest, 0x44: LDAPSearchResultEntry, 0x45: LDAPSearchResultDone, 0x46: LDAPModifyRequest, 0x47: LDAPModifyResponse, 0x48: LDAPAddRequest, 0x49: LDAPAddResponse, 0x4a: LDAPDelRequest, 0x4b: LDAPDelResponse, 0x4c: LDAPModifyDNRequest, 0x4d: LDAPModifyDNResponse, 0x50: LDAPAbandonRequest, 0x83: LDAPReferral, 0x57: LDAPExtendedRequest, 0x58: LDAPExtendedResponse} fallback=<BERDecoderContext identities={0x01: BERBoolean, 0x02: BERInteger, 0x04: BEROctetString, 0x05: BERNull, 0x0a: BEREnumerated, 0x10: BERSequence, 0x11: BERSet} fallback=None inherit=None> inherit=None>>>¶
-
bind
(dn='', auth='')[source]¶ @depreciated: Use e.bind(auth).
@todo: Remove this method when there are no callers.
-
connectionLost
(reason=<twisted.python.failure.Failure twisted.internet.error.ConnectionDone: Connection was closed cleanly.>)[source]¶ Called when TCP connection has been lost
-
debug
= False¶
-
send
(op)[source]¶ Send an LDAP operation to the server.
@param op: the operation to send
@type op: LDAPProtocolRequest
@return: the response from server
@rtype: Deferred LDAPProtocolResponse
-
send_multiResponse
(op, handler, *args, **kwargs)[source]¶ Send an LDAP operation to the server, expecting one or more responses.
@param op: the operation to send
@type op: LDAPProtocolRequest
@param handler: a callable that will be called for each response. It should return a boolean, whether this was the final response.
@param args: positional arguments to pass to handler
@param kwargs: keyword arguments to pass to handler
@return: the result from the last handler as a deferred that completes when the last response has been received
@rtype: Deferred LDAPProtocolResponse
-
send_noResponse
(op)[source]¶ Send an LDAP operation to the server, with no response expected.
@param op: the operation to send @type op: LDAPProtocolRequest
-
-
exception
ldaptor.protocols.ldap.ldapclient.
LDAPClientConnectionLostException
(message=None)[source]¶
-
exception
ldaptor.protocols.ldap.ldapclient.
LDAPStartTLSBusyError
(onwire, message=None)[source]¶ Bases:
ldaptor.protocols.ldap.ldaperrors.LDAPOperationsError
-
class
ldaptor.protocols.ldap.ldapconnector.
LDAPClientCreator
(reactor, protocolClass, *args, **kwargs)[source]¶ Bases:
twisted.internet.protocol.ClientCreator
-
exception
ldaptor.protocols.ldap.ldaperrors.
LDAPAdminLimitExceeded
(message=None)¶ Bases:
ldaptor.protocols.ldap.ldaperrors.LDAPException
-
name
= 'adminLimitExceeded'¶
-
resultCode
= 11¶
-
-
exception
ldaptor.protocols.ldap.ldaperrors.
LDAPAffectsMultipleDSAs
(message=None)¶ Bases:
ldaptor.protocols.ldap.ldaperrors.LDAPException
-
name
= 'affectsMultipleDSAs'¶
-
resultCode
= 71¶
-
-
exception
ldaptor.protocols.ldap.ldaperrors.
LDAPAliasDereferencingProblem
(message=None)¶ Bases:
ldaptor.protocols.ldap.ldaperrors.LDAPException
-
name
= 'aliasDereferencingProblem'¶
-
resultCode
= 36¶
-
-
exception
ldaptor.protocols.ldap.ldaperrors.
LDAPAliasProblem
(message=None)¶ Bases:
ldaptor.protocols.ldap.ldaperrors.LDAPException
-
name
= 'aliasProblem'¶
-
resultCode
= 33¶
-
-
exception
ldaptor.protocols.ldap.ldaperrors.
LDAPAttributeOrValueExists
(message=None)¶ Bases:
ldaptor.protocols.ldap.ldaperrors.LDAPException
-
name
= 'attributeOrValueExists'¶
-
resultCode
= 20¶
-
-
exception
ldaptor.protocols.ldap.ldaperrors.
LDAPAuthMethodNotSupported
(message=None)¶ Bases:
ldaptor.protocols.ldap.ldaperrors.LDAPException
-
name
= 'authMethodNotSupported'¶
-
resultCode
= 7¶
-
-
exception
ldaptor.protocols.ldap.ldaperrors.
LDAPBusy
(message=None)¶ Bases:
ldaptor.protocols.ldap.ldaperrors.LDAPException
-
name
= 'busy'¶
-
resultCode
= 51¶
-
-
exception
ldaptor.protocols.ldap.ldaperrors.
LDAPCompareFalse
(message=None)¶ Bases:
ldaptor.protocols.ldap.ldaperrors.LDAPException
-
name
= 'compareFalse'¶
-
resultCode
= 5¶
-
-
exception
ldaptor.protocols.ldap.ldaperrors.
LDAPCompareTrue
(message=None)¶ Bases:
ldaptor.protocols.ldap.ldaperrors.LDAPException
-
name
= 'compareTrue'¶
-
resultCode
= 6¶
-
-
exception
ldaptor.protocols.ldap.ldaperrors.
LDAPConfidentialityRequired
(message=None)¶ Bases:
ldaptor.protocols.ldap.ldaperrors.LDAPException
-
name
= 'confidentialityRequired'¶
-
resultCode
= 13¶
-
-
exception
ldaptor.protocols.ldap.ldaperrors.
LDAPConstraintViolation
(message=None)¶ Bases:
ldaptor.protocols.ldap.ldaperrors.LDAPException
-
name
= 'constraintViolation'¶
-
resultCode
= 19¶
-
-
exception
ldaptor.protocols.ldap.ldaperrors.
LDAPEntryAlreadyExists
(message=None)¶ Bases:
ldaptor.protocols.ldap.ldaperrors.LDAPException
-
name
= 'entryAlreadyExists'¶
-
resultCode
= 68¶
-
-
exception
ldaptor.protocols.ldap.ldaperrors.
LDAPException
(message=None)[source]¶ Bases:
exceptions.Exception
,ldaptor.protocols.ldap.ldaperrors.LDAPResult
-
message
¶
-
-
exception
ldaptor.protocols.ldap.ldaperrors.
LDAPInappropriateAuthentication
(message=None)¶ Bases:
ldaptor.protocols.ldap.ldaperrors.LDAPException
-
name
= 'inappropriateAuthentication'¶
-
resultCode
= 48¶
-
-
exception
ldaptor.protocols.ldap.ldaperrors.
LDAPInappropriateMatching
(message=None)¶ Bases:
ldaptor.protocols.ldap.ldaperrors.LDAPException
-
name
= 'inappropriateMatching'¶
-
resultCode
= 18¶
-
-
exception
ldaptor.protocols.ldap.ldaperrors.
LDAPInsufficientAccessRights
(message=None)¶ Bases:
ldaptor.protocols.ldap.ldaperrors.LDAPException
-
name
= 'insufficientAccessRights'¶
-
resultCode
= 50¶
-
-
exception
ldaptor.protocols.ldap.ldaperrors.
LDAPInvalidAttributeSyntax
(message=None)¶ Bases:
ldaptor.protocols.ldap.ldaperrors.LDAPException
-
name
= 'invalidAttributeSyntax'¶
-
resultCode
= 21¶
-
-
exception
ldaptor.protocols.ldap.ldaperrors.
LDAPInvalidCredentials
(message=None)¶ Bases:
ldaptor.protocols.ldap.ldaperrors.LDAPException
-
name
= 'invalidCredentials'¶
-
resultCode
= 49¶
-
-
exception
ldaptor.protocols.ldap.ldaperrors.
LDAPInvalidDNSyntax
(message=None)¶ Bases:
ldaptor.protocols.ldap.ldaperrors.LDAPException
-
name
= 'invalidDNSyntax'¶
-
resultCode
= 34¶
-
-
exception
ldaptor.protocols.ldap.ldaperrors.
LDAPLoopDetect
(message=None)¶ Bases:
ldaptor.protocols.ldap.ldaperrors.LDAPException
-
name
= 'loopDetect'¶
-
resultCode
= 54¶
-
-
exception
ldaptor.protocols.ldap.ldaperrors.
LDAPNamingViolation
(message=None)¶ Bases:
ldaptor.protocols.ldap.ldaperrors.LDAPException
-
name
= 'namingViolation'¶
-
resultCode
= 64¶
-
-
exception
ldaptor.protocols.ldap.ldaperrors.
LDAPNoSuchAttribute
(message=None)¶ Bases:
ldaptor.protocols.ldap.ldaperrors.LDAPException
-
name
= 'noSuchAttribute'¶
-
resultCode
= 16¶
-
-
exception
ldaptor.protocols.ldap.ldaperrors.
LDAPNoSuchObject
(message=None)¶ Bases:
ldaptor.protocols.ldap.ldaperrors.LDAPException
-
name
= 'noSuchObject'¶
-
resultCode
= 32¶
-
-
exception
ldaptor.protocols.ldap.ldaperrors.
LDAPNotAllowedOnNonLeaf
(message=None)¶ Bases:
ldaptor.protocols.ldap.ldaperrors.LDAPException
-
name
= 'notAllowedOnNonLeaf'¶
-
resultCode
= 66¶
-
-
exception
ldaptor.protocols.ldap.ldaperrors.
LDAPNotAllowedOnRDN
(message=None)¶ Bases:
ldaptor.protocols.ldap.ldaperrors.LDAPException
-
name
= 'notAllowedOnRDN'¶
-
resultCode
= 67¶
-
-
exception
ldaptor.protocols.ldap.ldaperrors.
LDAPObjectClassModsProhibited
(message=None)¶ Bases:
ldaptor.protocols.ldap.ldaperrors.LDAPException
-
name
= 'objectClassModsProhibited'¶
-
resultCode
= 69¶
-
-
exception
ldaptor.protocols.ldap.ldaperrors.
LDAPObjectClassViolation
(message=None)¶ Bases:
ldaptor.protocols.ldap.ldaperrors.LDAPException
-
name
= 'objectClassViolation'¶
-
resultCode
= 65¶
-
-
exception
ldaptor.protocols.ldap.ldaperrors.
LDAPOperationsError
(message=None)¶ Bases:
ldaptor.protocols.ldap.ldaperrors.LDAPException
-
name
= 'operationsError'¶
-
resultCode
= 1¶
-
-
exception
ldaptor.protocols.ldap.ldaperrors.
LDAPOther
(message=None)¶ Bases:
ldaptor.protocols.ldap.ldaperrors.LDAPException
-
name
= 'other'¶
-
resultCode
= 80¶
-
-
exception
ldaptor.protocols.ldap.ldaperrors.
LDAPProtocolError
(message=None)¶ Bases:
ldaptor.protocols.ldap.ldaperrors.LDAPException
-
name
= 'protocolError'¶
-
resultCode
= 2¶
-
-
exception
ldaptor.protocols.ldap.ldaperrors.
LDAPReferral
(message=None)¶ Bases:
ldaptor.protocols.ldap.ldaperrors.LDAPException
-
name
= 'referral'¶
-
resultCode
= 10¶
-
-
exception
ldaptor.protocols.ldap.ldaperrors.
LDAPSaslBindInProgress
(message=None)¶ Bases:
ldaptor.protocols.ldap.ldaperrors.LDAPException
-
name
= 'saslBindInProgress'¶
-
resultCode
= 14¶
-
-
exception
ldaptor.protocols.ldap.ldaperrors.
LDAPSizeLimitExceeded
(message=None)¶ Bases:
ldaptor.protocols.ldap.ldaperrors.LDAPException
-
name
= 'sizeLimitExceeded'¶
-
resultCode
= 4¶
-
-
exception
ldaptor.protocols.ldap.ldaperrors.
LDAPStrongAuthRequired
(message=None)¶ Bases:
ldaptor.protocols.ldap.ldaperrors.LDAPException
-
name
= 'strongAuthRequired'¶
-
resultCode
= 8¶
-
-
exception
ldaptor.protocols.ldap.ldaperrors.
LDAPTimeLimitExceeded
(message=None)¶ Bases:
ldaptor.protocols.ldap.ldaperrors.LDAPException
-
name
= 'timeLimitExceeded'¶
-
resultCode
= 3¶
-
-
exception
ldaptor.protocols.ldap.ldaperrors.
LDAPUndefinedAttributeType
(message=None)¶ Bases:
ldaptor.protocols.ldap.ldaperrors.LDAPException
-
name
= 'undefinedAttributeType'¶
-
resultCode
= 17¶
-
-
exception
ldaptor.protocols.ldap.ldaperrors.
LDAPUnknownError
(resultCode, message=None)[source]¶ Bases:
ldaptor.protocols.ldap.ldaperrors.LDAPException
-
resultCode
= None¶
-
-
exception
ldaptor.protocols.ldap.ldaperrors.
LDAPUnwillingToPerform
(message=None)¶ Bases:
ldaptor.protocols.ldap.ldaperrors.LDAPException
-
name
= 'unwillingToPerform'¶
-
resultCode
= 53¶
-
-
class
ldaptor.protocols.ldap.ldaperrors.
Success
(msg)[source]¶ Bases:
ldaptor.protocols.ldap.ldaperrors.LDAPResult
-
name
= 'success'¶
-
resultCode
= 0¶
-
LDAP protocol server
-
class
ldaptor.protocols.ldap.ldapserver.
BaseLDAPServer
[source]¶ Bases:
twisted.internet.protocol.Protocol
-
berdecoder
= <LDAPBERDecoderContext_TopLevel identities={0x10: LDAPMessage} fallback=None inherit=<LDAPBERDecoderContext_LDAPMessage identities={0x80: LDAPControls, 0x53: LDAPSearchResultReference} fallback=<LDAPBERDecoderContext identities={0x40: LDAPBindRequest, 0x41: LDAPBindResponse, 0x42: LDAPUnbindRequest, 0x43: LDAPSearchRequest, 0x44: LDAPSearchResultEntry, 0x45: LDAPSearchResultDone, 0x46: LDAPModifyRequest, 0x47: LDAPModifyResponse, 0x48: LDAPAddRequest, 0x49: LDAPAddResponse, 0x4a: LDAPDelRequest, 0x4b: LDAPDelResponse, 0x4c: LDAPModifyDNRequest, 0x4d: LDAPModifyDNResponse, 0x50: LDAPAbandonRequest, 0x83: LDAPReferral, 0x57: LDAPExtendedRequest, 0x58: LDAPExtendedResponse} fallback=<BERDecoderContext identities={0x01: BERBoolean, 0x02: BERInteger, 0x04: BEROctetString, 0x05: BERNull, 0x0a: BEREnumerated, 0x10: BERSequence, 0x11: BERSet} fallback=None inherit=None> inherit=None> inherit=<LDAPBERDecoderContext identities={0x40: LDAPBindRequest, 0x41: LDAPBindResponse, 0x42: LDAPUnbindRequest, 0x43: LDAPSearchRequest, 0x44: LDAPSearchResultEntry, 0x45: LDAPSearchResultDone, 0x46: LDAPModifyRequest, 0x47: LDAPModifyResponse, 0x48: LDAPAddRequest, 0x49: LDAPAddResponse, 0x4a: LDAPDelRequest, 0x4b: LDAPDelResponse, 0x4c: LDAPModifyDNRequest, 0x4d: LDAPModifyDNResponse, 0x50: LDAPAbandonRequest, 0x83: LDAPReferral, 0x57: LDAPExtendedRequest, 0x58: LDAPExtendedResponse} fallback=<BERDecoderContext identities={0x01: BERBoolean, 0x02: BERInteger, 0x04: BEROctetString, 0x05: BERNull, 0x0a: BEREnumerated, 0x10: BERSequence, 0x11: BERSet} fallback=None inherit=None> inherit=None>>>¶
-
connectionLost
(reason=<twisted.python.failure.Failure twisted.internet.error.ConnectionDone: Connection was closed cleanly.>)[source]¶ Called when TCP connection has been lost
-
debug
= False¶
-
-
class
ldaptor.protocols.ldap.ldapserver.
LDAPServer
[source]¶ Bases:
ldaptor.protocols.ldap.ldapserver.BaseLDAPServer
An LDAP server
-
boundUser
= None¶
-
fail_LDAPAddRequest
¶ alias of
LDAPAddResponse
-
fail_LDAPBindRequest
¶ alias of
LDAPBindResponse
-
fail_LDAPDelRequest
¶ alias of
LDAPDelResponse
-
fail_LDAPExtendedRequest
¶ alias of
LDAPExtendedResponse
-
fail_LDAPModifyDNRequest
¶ alias of
LDAPModifyDNResponse
-
fail_LDAPModifyRequest
¶ alias of
LDAPModifyResponse
-
fail_LDAPSearchRequest
¶ alias of
LDAPSearchResultDone
-
Pythonic API for LDAP operations.
-
exception
ldaptor.protocols.ldap.ldapsyntax.
CannotRemoveRDNError
(key, val=None)[source]¶ Bases:
exceptions.Exception
The attribute to be removed is the RDN for the object and cannot be removed.
-
exception
ldaptor.protocols.ldap.ldapsyntax.
DNNotPresentError
[source]¶ Bases:
exceptions.Exception
The requested DN cannot be found by the server.
-
ldaptor.protocols.ldap.ldapsyntax.
LDAPEntry
¶ alias of
LDAPEntryWithClient
-
class
ldaptor.protocols.ldap.ldapsyntax.
LDAPEntryWithAutoFill
(*args, **kwargs)[source]¶ Bases:
ldaptor.protocols.ldap.ldapsyntax.LDAPEntryWithClient
-
class
ldaptor.protocols.ldap.ldapsyntax.
LDAPEntryWithClient
(client, dn, attributes={}, complete=0)[source]¶ Bases:
ldaptor.entry.EditableLDAPEntry
-
journal
(journalOperation)[source]¶ Add a Modification into the list of modifications that need to be flushed to the LDAP server.
Normal callers should not use this, they should use the o[‘foo’]=[‘bar’, ‘baz’] -style API that enforces schema, handles errors and updates the cached data.
-
search
(filterText=None, filterObject=None, attributes=(), scope=None, derefAliases=None, sizeLimit=0, sizeLimitIsNonFatal=False, timeLimit=0, typesOnly=0, callback=None)[source]¶
-
setPasswordMaybe_ExtendedOperation
(newPasswd)¶ Set the password on this object.
@param newPasswd: A string containing the new password.
@return: A Deferred that will complete when the operation is done.
-
setPasswordMaybe_Samba
(newPasswd)[source]¶ Set the Samba password on this object if it is a sambaSamAccount or sambaAccount.
@param newPasswd: A string containing the new password.
@return: A Deferred that will complete when the operation is done.
-
setPassword_ExtendedOperation
(newPasswd)[source]¶ Set the password on this object.
@param newPasswd: A string containing the new password.
@return: A Deferred that will complete when the operation is done.
-
setPassword_Samba
(newPasswd, style=None)[source]¶ Set the Samba password on this object.
@param newPasswd: A string containing the new password.
@param style: one of ‘sambaSamAccount’, ‘sambaAccount’ or None. Specifies the style of samba accounts used. None is default and is the same as ‘sambaSamAccount’.
@return: A Deferred that will complete when the operation is done.
-
-
exception
ldaptor.protocols.ldap.ldapsyntax.
MatchNotImplemented
(op)[source]¶ Bases:
exceptions.NotImplementedError
Match type not implemented
-
exception
ldaptor.protocols.ldap.ldapsyntax.
NoContainingNamingContext
[source]¶ Bases:
exceptions.Exception
The server contains to LDAP naming context that would contain this object.
-
exception
ldaptor.protocols.ldap.ldapsyntax.
ObjectDeletedError
[source]¶ Bases:
ldaptor.protocols.ldap.ldapsyntax.ObjectInBadStateError
The LDAP object has already been removed, unable to perform operations on it.
-
exception
ldaptor.protocols.ldap.ldapsyntax.
ObjectDirtyError
[source]¶ Bases:
ldaptor.protocols.ldap.ldapsyntax.ObjectInBadStateError
The LDAP object has a journal which needs to be committed or undone before this operation.
-
exception
ldaptor.protocols.ldap.ldapsyntax.
ObjectInBadStateError
[source]¶ Bases:
exceptions.Exception
The LDAP object in in a bad state.
Support for writing a set of directory entries as LDIF. You probably want to use this only indirectly, as in str(LDAPEntry(...)).
TODO support writing modify operations TODO support reading modify operations
TODO implement rest of syntax from RFC2849
-
class
ldaptor.protocols.ldap.ldifdelta.
LDIFDelta
[source]¶ Bases:
ldaptor.protocols.ldap.ldifprotocol.LDIF
-
MOD_SPEC_TO_DELTA
= {'add': <class 'ldaptor.delta.Add'>, 'replace': <class 'ldaptor.delta.Replace'>, 'delete': <class 'ldaptor.delta.Delete'>}¶
-
-
exception
ldaptor.protocols.ldap.ldifdelta.
LDIFDeltaAddMissingAttributesError
[source]¶ Bases:
ldaptor.protocols.ldap.ldifprotocol.LDIFParseError
Add operation needs to have atleast one attribute type and value.
-
exception
ldaptor.protocols.ldap.ldifdelta.
LDIFDeltaDeleteHasJunkAfterChangeTypeError
[source]¶ Bases:
ldaptor.protocols.ldap.ldifprotocol.LDIFParseError
Delete operation takes no attribute types or values.
-
exception
ldaptor.protocols.ldap.ldifdelta.
LDIFDeltaMissingChangeTypeError
[source]¶ Bases:
ldaptor.protocols.ldap.ldifprotocol.LDIFParseError
LDIF delta entry has no changetype.
-
exception
ldaptor.protocols.ldap.ldifdelta.
LDIFDeltaModificationDifferentAttributeTypeError
[source]¶ Bases:
ldaptor.protocols.ldap.ldifprotocol.LDIFParseError
The attribute type for the change is not the as in the mod-spec header line.
-
exception
ldaptor.protocols.ldap.ldifdelta.
LDIFDeltaModificationMissingEndDashError
[source]¶ Bases:
ldaptor.protocols.ldap.ldifprotocol.LDIFParseError
LDIF delta modification has no ending dash.
-
exception
ldaptor.protocols.ldap.ldifdelta.
LDIFDeltaUnknownModificationError
[source]¶ Bases:
ldaptor.protocols.ldap.ldifprotocol.LDIFParseError
LDIF delta modification has unknown mod-spec.
-
class
ldaptor.protocols.ldap.ldifprotocol.
LDIF
[source]¶ Bases:
object
,twisted.protocols.basic.LineReceiver
-
connectionLost
(reason=<twisted.python.failure.Failure twisted.internet.error.ConnectionDone: Connection was closed cleanly.>)[source]¶
-
data
= None¶
-
delimiter
= '\n'¶
-
dn
= None¶
-
lastLine
= None¶
-
mode
= 'HEADER'¶
-
version
= None¶
-
-
exception
ldaptor.protocols.ldap.ldifprotocol.
LDIFEntryStartsWithNonDNError
[source]¶ Bases:
ldaptor.protocols.ldap.ldifprotocol.LDIFParseError
LDIF entry starts with a non-DN line
-
exception
ldaptor.protocols.ldap.ldifprotocol.
LDIFEntryStartsWithSpaceError
[source]¶ Bases:
ldaptor.protocols.ldap.ldifprotocol.LDIFParseError
Invalid LDIF value format
-
exception
ldaptor.protocols.ldap.ldifprotocol.
LDIFLineWithoutSemicolonError
[source]¶ Bases:
ldaptor.protocols.ldap.ldifprotocol.LDIFParseError
LDIF line without semicolon seen
-
exception
ldaptor.protocols.ldap.ldifprotocol.
LDIFParseError
[source]¶ Bases:
exceptions.Exception
Error parsing LDIF.
-
exception
ldaptor.protocols.ldap.ldifprotocol.
LDIFTruncatedError
[source]¶ Bases:
ldaptor.protocols.ldap.ldifprotocol.LDIFParseError
LDIF appears to be truncated
-
exception
ldaptor.protocols.ldap.ldifprotocol.
LDIFUnsupportedVersionError
[source]¶ Bases:
ldaptor.protocols.ldap.ldifprotocol.LDIFParseError
LDIF version not supported
-
exception
ldaptor.protocols.ldap.ldifprotocol.
LDIFVersionNotANumberError
[source]¶ Bases:
ldaptor.protocols.ldap.ldifprotocol.LDIFParseError
Non-numeric LDIF version number
LDAP protocol proxy server
-
class
ldaptor.protocols.ldap.svcbindproxy.
ServiceBindingProxy
(services=None, fallback=None, *a, **kw)[source]¶ Bases:
ldaptor.protocols.ldap.proxy.Proxy
An LDAP proxy that handles non-anonymous bind requests specially.
BindRequests are intercepted and authentication is attempted against each configured service. This authentication is performed against a separate LDAP entry, found by searching for entries with
- objectClass: serviceSecurityObject
- owner: the DN of the original bind attempt
- cn: the service name.
starting at the identity-base as configured in the config file.
Finally, if the authentication does not succeed against any of the configured services, the proxy can fallback to passing the bind request to the real server.
-
fail_LDAPBindRequest
¶ alias of
LDAPBindResponse
-
fallback
= False¶
-
services
= []¶
LDAP protocol logic
Pure, simple, BER encoding and decoding
-
class
ldaptor.protocols.pureber.
BERBoolean
(value=None, tag=None)[source]¶ Bases:
ldaptor.protocols.pureber.BERBase
-
tag
= 1¶
-
-
class
ldaptor.protocols.pureber.
BERDecoderContext
(fallback=None, inherit=None)[source]¶ -
Identities
= {1: <class ldaptor.protocols.pureber.BERBoolean at 0x7ff1d754a3f8>, 2: <class ldaptor.protocols.pureber.BERInteger at 0x7ff1d754a2c0>, 4: <class ldaptor.protocols.pureber.BEROctetString at 0x7ff1d754a328>, 5: <class ldaptor.protocols.pureber.BERNull at 0x7ff1d754a390>, 10: <class ldaptor.protocols.pureber.BEREnumerated at 0x7ff1d754a460>, 16: <class 'ldaptor.protocols.pureber.BERSequence'>, 17: <class 'ldaptor.protocols.pureber.BERSet'>}¶
-
-
class
ldaptor.protocols.pureber.
BEREnumerated
(value=None, tag=None)[source]¶ Bases:
ldaptor.protocols.pureber.BERInteger
-
tag
= 10¶
-
-
exception
ldaptor.protocols.pureber.
BERExceptionInsufficientData
[source]¶ Bases:
exceptions.Exception
-
class
ldaptor.protocols.pureber.
BERInteger
(value=None, tag=None)[source]¶ Bases:
ldaptor.protocols.pureber.BERBase
-
tag
= 2¶
-
value
= None¶
-
-
class
ldaptor.protocols.pureber.
BERNull
(tag=None)[source]¶ Bases:
ldaptor.protocols.pureber.BERBase
-
tag
= 5¶
-
-
class
ldaptor.protocols.pureber.
BEROctetString
(value=None, tag=None)[source]¶ Bases:
ldaptor.protocols.pureber.BERBase
-
tag
= 4¶
-
value
= None¶
-
-
class
ldaptor.protocols.pureber.
BERSequence
(value=None, tag=None)[source]¶ Bases:
ldaptor.protocols.pureber.BERStructured
,UserList.UserList
-
tag
= 16¶
-
-
class
ldaptor.protocols.pureber.
BERSet
(value=None, tag=None)[source]¶ Bases:
ldaptor.protocols.pureber.BERSequence
-
tag
= 17¶
-
-
exception
ldaptor.protocols.pureber.
UnknownBERTag
(tag, context)[source]¶ Bases:
exceptions.Exception
-
ldaptor.protocols.pureber.
berDecodeLength
(m, offset=0)[source]¶ Return a tuple of (length, lengthLength). m must be atleast one byte long.
-
ldaptor.protocols.pureber.
berDecodeMultiple
(content, berdecoder) → [objects][source]¶ Decodes everything in content and returns a list of decoded objects.
All of content will be decoded, and content must contain complete BER objects.
LDAP protocol message conversion; no application logic here.
-
class
ldaptor.protocols.pureldap.
LDAPAbandonRequest
(value=None, id=None, tag=None)[source]¶ Bases:
ldaptor.protocols.pureldap.LDAPProtocolRequest
,ldaptor.protocols.pureldap.LDAPInteger
-
needs_answer
= 0¶
-
tag
= 80¶
-
-
class
ldaptor.protocols.pureldap.
LDAPAddRequest
(entry=None, attributes=None, tag=None)[source]¶ Bases:
ldaptor.protocols.pureldap.LDAPProtocolRequest
,ldaptor.protocols.pureber.BERSequence
-
tag
= 72¶
-
-
class
ldaptor.protocols.pureldap.
LDAPAddResponse
(resultCode=None, matchedDN=None, errorMessage=None, referral=None, serverSaslCreds=None, tag=None)[source]¶ Bases:
ldaptor.protocols.pureldap.LDAPResult
-
tag
= 73¶
-
-
class
ldaptor.protocols.pureldap.
LDAPAttributeValueAssertion
(attributeDesc=None, assertionValue=None, tag=None)[source]¶
-
class
ldaptor.protocols.pureldap.
LDAPBERDecoderContext
(fallback=None, inherit=None)[source]¶ Bases:
ldaptor.protocols.pureber.BERDecoderContext
-
Identities
= {64: <class 'ldaptor.protocols.pureldap.LDAPBindRequest'>, 65: <class 'ldaptor.protocols.pureldap.LDAPBindResponse'>, 66: <class ldaptor.protocols.pureldap.LDAPUnbindRequest at 0x7ff1d754a8d8>, 67: <class 'ldaptor.protocols.pureldap.LDAPSearchRequest'>, 68: <class 'ldaptor.protocols.pureldap.LDAPSearchResultEntry'>, 69: <class 'ldaptor.protocols.pureldap.LDAPSearchResultDone'>, 70: <class 'ldaptor.protocols.pureldap.LDAPModifyRequest'>, 71: <class 'ldaptor.protocols.pureldap.LDAPModifyResponse'>, 72: <class 'ldaptor.protocols.pureldap.LDAPAddRequest'>, 73: <class 'ldaptor.protocols.pureldap.LDAPAddResponse'>, 74: <class ldaptor.protocols.pureldap.LDAPDelRequest at 0x7ff1d7576188>, 75: <class 'ldaptor.protocols.pureldap.LDAPDelResponse'>, 76: <class 'ldaptor.protocols.pureldap.LDAPModifyDNRequest'>, 77: <class 'ldaptor.protocols.pureldap.LDAPModifyDNResponse'>, 80: <class ldaptor.protocols.pureldap.LDAPAbandonRequest at 0x7ff1d75762c0>, 131: <class 'ldaptor.protocols.pureldap.LDAPReferral'>, 87: <class 'ldaptor.protocols.pureldap.LDAPExtendedRequest'>, 88: <class 'ldaptor.protocols.pureldap.LDAPExtendedResponse'>}¶
-
-
class
ldaptor.protocols.pureldap.
LDAPBERDecoderContext_BindResponse
(fallback=None, inherit=None)[source]¶ Bases:
ldaptor.protocols.pureber.BERDecoderContext
-
Identities
= {135: <class ldaptor.protocols.pureldap.LDAPBindResponse_serverSaslCreds at 0x7ff1d754a808>}¶
-
-
class
ldaptor.protocols.pureldap.
LDAPBERDecoderContext_Filter
(fallback=None, inherit=None)[source]¶ Bases:
ldaptor.protocols.pureber.BERDecoderContext
-
Identities
= {128: <class 'ldaptor.protocols.pureldap.LDAPFilter_and'>, 129: <class 'ldaptor.protocols.pureldap.LDAPFilter_or'>, 130: <class ldaptor.protocols.pureldap.LDAPFilter_not at 0x7ff1d754aa10>, 131: <class 'ldaptor.protocols.pureldap.LDAPFilter_equalityMatch'>, 132: <class 'ldaptor.protocols.pureldap.LDAPFilter_substrings'>, 133: <class 'ldaptor.protocols.pureldap.LDAPFilter_greaterOrEqual'>, 134: <class 'ldaptor.protocols.pureldap.LDAPFilter_lessOrEqual'>, 135: <class ldaptor.protocols.pureldap.LDAPFilter_present at 0x7ff1d754ac18>, 136: <class 'ldaptor.protocols.pureldap.LDAPFilter_approxMatch'>, 137: <class 'ldaptor.protocols.pureldap.LDAPFilter_extensibleMatch'>}¶
-
-
class
ldaptor.protocols.pureldap.
LDAPBERDecoderContext_Filter_substrings
(fallback=None, inherit=None)[source]¶ Bases:
ldaptor.protocols.pureber.BERDecoderContext
-
Identities
= {128: <class ldaptor.protocols.pureldap.LDAPFilter_substrings_initial at 0x7ff1d754aa78>, 129: <class ldaptor.protocols.pureldap.LDAPFilter_substrings_any at 0x7ff1d754aae0>, 130: <class ldaptor.protocols.pureldap.LDAPFilter_substrings_final at 0x7ff1d754ab48>}¶
-
-
class
ldaptor.protocols.pureldap.
LDAPBERDecoderContext_LDAPBindRequest
(fallback=None, inherit=None)[source]¶ Bases:
ldaptor.protocols.pureber.BERDecoderContext
-
Identities
= {128: <class ldaptor.protocols.pureber.BEROctetString at 0x7ff1d754a328>, 131: <class 'ldaptor.protocols.pureber.BERSequence'>}¶
-
-
class
ldaptor.protocols.pureldap.
LDAPBERDecoderContext_LDAPControls
(fallback=None, inherit=None)[source]¶ Bases:
ldaptor.protocols.pureber.BERDecoderContext
-
Identities
= {16: <class 'ldaptor.protocols.pureldap.LDAPControl'>}¶
-
-
class
ldaptor.protocols.pureldap.
LDAPBERDecoderContext_LDAPExtendedRequest
(fallback=None, inherit=None)[source]¶ Bases:
ldaptor.protocols.pureber.BERDecoderContext
-
Identities
= {128: <class ldaptor.protocols.pureber.BEROctetString at 0x7ff1d754a328>, 129: <class ldaptor.protocols.pureber.BEROctetString at 0x7ff1d754a328>}¶
-
-
class
ldaptor.protocols.pureldap.
LDAPBERDecoderContext_LDAPExtendedResponse
(fallback=None, inherit=None)[source]¶ Bases:
ldaptor.protocols.pureber.BERDecoderContext
-
Identities
= {138: <class ldaptor.protocols.pureldap.LDAPResponseName at 0x7ff1d7576390>, 139: <class ldaptor.protocols.pureldap.LDAPResponse at 0x7ff1d75763f8>}¶
-
-
class
ldaptor.protocols.pureldap.
LDAPBERDecoderContext_LDAPMessage
(fallback=None, inherit=None)[source]¶ Bases:
ldaptor.protocols.pureber.BERDecoderContext
-
Identities
= {128: <class 'ldaptor.protocols.pureldap.LDAPControls'>, 83: <class ldaptor.protocols.pureldap.LDAPSearchResultReference at 0x7ff1d754a7a0>}¶
-
-
class
ldaptor.protocols.pureldap.
LDAPBERDecoderContext_LDAPPasswordModifyRequest
(fallback=None, inherit=None)[source]¶ Bases:
ldaptor.protocols.pureber.BERDecoderContext
-
Identities
= {128: <class ldaptor.protocols.pureldap.LDAPPasswordModifyRequest_userIdentity at 0x7ff1d75764c8>, 129: <class ldaptor.protocols.pureldap.LDAPPasswordModifyRequest_oldPasswd at 0x7ff1d7576530>, 130: <class ldaptor.protocols.pureldap.LDAPPasswordModifyRequest_newPasswd at 0x7ff1d7576598>}¶
-
-
class
ldaptor.protocols.pureldap.
LDAPBERDecoderContext_MatchingRuleAssertion
(fallback=None, inherit=None)[source]¶ Bases:
ldaptor.protocols.pureber.BERDecoderContext
-
Identities
= {129: <class ldaptor.protocols.pureldap.LDAPMatchingRuleAssertion_matchingRule at 0x7ff1d754ad50>, 130: <class ldaptor.protocols.pureldap.LDAPMatchingRuleAssertion_type at 0x7ff1d754adb8>, 131: <class ldaptor.protocols.pureldap.LDAPMatchingRuleAssertion_matchValue at 0x7ff1d754ae20>, 132: <class ldaptor.protocols.pureldap.LDAPMatchingRuleAssertion_dnAttributes at 0x7ff1d754ae88>}¶
-
-
class
ldaptor.protocols.pureldap.
LDAPBERDecoderContext_ModifyDNRequest
(fallback=None, inherit=None)[source]¶ Bases:
ldaptor.protocols.pureber.BERDecoderContext
-
Identities
= {128: <class ldaptor.protocols.pureldap.LDAPModifyDNResponse_newSuperior at 0x7ff1d75761f0>}¶
-
-
class
ldaptor.protocols.pureldap.
LDAPBERDecoderContext_TopLevel
(fallback=None, inherit=None)[source]¶ Bases:
ldaptor.protocols.pureber.BERDecoderContext
-
Identities
= {16: <class 'ldaptor.protocols.pureldap.LDAPMessage'>}¶
-
-
class
ldaptor.protocols.pureldap.
LDAPBindRequest
(version=None, dn=None, auth=None, tag=None, sasl=False)[source]¶ Bases:
ldaptor.protocols.pureldap.LDAPProtocolRequest
,ldaptor.protocols.pureber.BERSequence
-
tag
= 64¶
-
-
class
ldaptor.protocols.pureldap.
LDAPBindResponse
(resultCode=None, matchedDN=None, errorMessage=None, referral=None, serverSaslCreds=None, tag=None)[source]¶ Bases:
ldaptor.protocols.pureldap.LDAPResult
-
errorMessage
= None¶
-
matchedDN
= None¶
-
referral
= None¶
-
resultCode
= None¶
-
serverSaslCreds
= None¶
-
tag
= 65¶
-
-
class
ldaptor.protocols.pureldap.
LDAPBindResponse_serverSaslCreds
(value=None, tag=None)[source]¶ Bases:
ldaptor.protocols.pureber.BEROctetString
-
tag
= 135¶
-
-
class
ldaptor.protocols.pureldap.
LDAPControl
(controlType, criticality=None, controlValue=None, id=None, tag=None)[source]¶ Bases:
ldaptor.protocols.pureber.BERSequence
-
controlValue
= None¶
-
criticality
= None¶
-
-
class
ldaptor.protocols.pureldap.
LDAPControls
(value=None, tag=None)[source]¶ Bases:
ldaptor.protocols.pureber.BERSequence
-
tag
= 128¶
-
-
class
ldaptor.protocols.pureldap.
LDAPDelRequest
(value=None, entry=None, tag=None)[source]¶ Bases:
ldaptor.protocols.pureldap.LDAPProtocolRequest
,ldaptor.protocols.pureldap.LDAPString
-
tag
= 74¶
-
-
class
ldaptor.protocols.pureldap.
LDAPDelResponse
(resultCode=None, matchedDN=None, errorMessage=None, referral=None, serverSaslCreds=None, tag=None)[source]¶ Bases:
ldaptor.protocols.pureldap.LDAPResult
-
tag
= 75¶
-
-
class
ldaptor.protocols.pureldap.
LDAPExtendedRequest
(requestName=None, requestValue=None, tag=None)[source]¶ Bases:
ldaptor.protocols.pureldap.LDAPProtocolRequest
,ldaptor.protocols.pureber.BERSequence
-
requestName
= None¶
-
requestValue
= None¶
-
tag
= 87¶
-
-
class
ldaptor.protocols.pureldap.
LDAPExtendedResponse
(resultCode=None, matchedDN=None, errorMessage=None, referral=None, serverSaslCreds=None, responseName=None, response=None, tag=None)[source]¶ Bases:
ldaptor.protocols.pureldap.LDAPResult
-
response
= None¶
-
responseName
= None¶
-
tag
= 88¶
-
-
class
ldaptor.protocols.pureldap.
LDAPFilter_and
(value=None, tag=None)[source]¶ Bases:
ldaptor.protocols.pureldap.LDAPFilterSet
-
tag
= 128¶
-
-
class
ldaptor.protocols.pureldap.
LDAPFilter_approxMatch
(attributeDesc=None, assertionValue=None, tag=None)[source]¶ Bases:
ldaptor.protocols.pureldap.LDAPAttributeValueAssertion
-
tag
= 136¶
-
-
class
ldaptor.protocols.pureldap.
LDAPFilter_equalityMatch
(attributeDesc=None, assertionValue=None, tag=None)[source]¶ Bases:
ldaptor.protocols.pureldap.LDAPAttributeValueAssertion
-
tag
= 131¶
-
-
class
ldaptor.protocols.pureldap.
LDAPFilter_extensibleMatch
(matchingRule=None, type=None, matchValue=None, dnAttributes=None, tag=None)[source]¶ Bases:
ldaptor.protocols.pureldap.LDAPMatchingRuleAssertion
-
tag
= 137¶
-
-
class
ldaptor.protocols.pureldap.
LDAPFilter_greaterOrEqual
(attributeDesc=None, assertionValue=None, tag=None)[source]¶ Bases:
ldaptor.protocols.pureldap.LDAPAttributeValueAssertion
-
tag
= 133¶
-
-
class
ldaptor.protocols.pureldap.
LDAPFilter_lessOrEqual
(attributeDesc=None, assertionValue=None, tag=None)[source]¶ Bases:
ldaptor.protocols.pureldap.LDAPAttributeValueAssertion
-
tag
= 134¶
-
-
class
ldaptor.protocols.pureldap.
LDAPFilter_not
(value, tag=130)[source]¶ Bases:
ldaptor.protocols.pureldap.LDAPFilter
-
tag
= 130¶
-
-
class
ldaptor.protocols.pureldap.
LDAPFilter_or
(value=None, tag=None)[source]¶ Bases:
ldaptor.protocols.pureldap.LDAPFilterSet
-
tag
= 129¶
-
-
class
ldaptor.protocols.pureldap.
LDAPFilter_present
(value=None, tag=None)[source]¶ Bases:
ldaptor.protocols.pureldap.LDAPAttributeDescription
-
tag
= 135¶
-
-
class
ldaptor.protocols.pureldap.
LDAPFilter_substrings
(type=None, substrings=None, tag=None)[source]¶ Bases:
ldaptor.protocols.pureber.BERSequence
-
tag
= 132¶
-
-
class
ldaptor.protocols.pureldap.
LDAPFilter_substrings_any
(value=None, tag=None)[source]¶ Bases:
ldaptor.protocols.pureldap.LDAPString
-
tag
= 129¶
-
-
class
ldaptor.protocols.pureldap.
LDAPFilter_substrings_final
(value=None, tag=None)[source]¶ Bases:
ldaptor.protocols.pureldap.LDAPString
-
tag
= 130¶
-
-
class
ldaptor.protocols.pureldap.
LDAPFilter_substrings_initial
(value=None, tag=None)[source]¶ Bases:
ldaptor.protocols.pureldap.LDAPString
-
tag
= 128¶
-
-
class
ldaptor.protocols.pureldap.
LDAPMatchingRuleAssertion
(matchingRule=None, type=None, matchValue=None, dnAttributes=None, tag=None)[source]¶ Bases:
ldaptor.protocols.pureber.BERSequence
-
dnAttributes
= None¶
-
matchValue
= None¶
-
matchingRule
= None¶
-
type
= None¶
-
-
class
ldaptor.protocols.pureldap.
LDAPMatchingRuleAssertion_dnAttributes
(value=None, tag=None)[source]¶ Bases:
ldaptor.protocols.pureber.BERBoolean
-
tag
= 132¶
-
-
class
ldaptor.protocols.pureldap.
LDAPMatchingRuleAssertion_matchValue
(value=None, tag=None)[source]¶ Bases:
ldaptor.protocols.pureldap.LDAPAssertionValue
-
tag
= 131¶
-
-
class
ldaptor.protocols.pureldap.
LDAPMatchingRuleAssertion_matchingRule
(value=None, tag=None)[source]¶ Bases:
ldaptor.protocols.pureldap.LDAPMatchingRuleId
-
tag
= 129¶
-
-
class
ldaptor.protocols.pureldap.
LDAPMatchingRuleAssertion_type
(value=None, tag=None)[source]¶ Bases:
ldaptor.protocols.pureldap.LDAPAttributeDescription
-
tag
= 130¶
-
-
class
ldaptor.protocols.pureldap.
LDAPMessage
(value=None, controls=None, id=None, tag=None)[source]¶ Bases:
ldaptor.protocols.pureber.BERSequence
-
id
= None¶
-
value
= None¶
-
-
class
ldaptor.protocols.pureldap.
LDAPModifyDNRequest
(entry, newrdn, deleteoldrdn, newSuperior=None, tag=None)[source]¶ Bases:
ldaptor.protocols.pureldap.LDAPProtocolRequest
,ldaptor.protocols.pureber.BERSequence
-
deleteoldrdn
= None¶
-
entry
= None¶
-
newSuperior
= None¶
-
newrdn
= None¶
-
tag
= 76¶
-
-
class
ldaptor.protocols.pureldap.
LDAPModifyDNResponse
(resultCode=None, matchedDN=None, errorMessage=None, referral=None, serverSaslCreds=None, tag=None)[source]¶ Bases:
ldaptor.protocols.pureldap.LDAPResult
-
tag
= 77¶
-
-
class
ldaptor.protocols.pureldap.
LDAPModifyDNResponse_newSuperior
(value=None, tag=None)[source]¶ Bases:
ldaptor.protocols.pureldap.LDAPString
-
tag
= 128¶
-
-
class
ldaptor.protocols.pureldap.
LDAPModifyRequest
(object=None, modification=None, tag=None)[source]¶ Bases:
ldaptor.protocols.pureldap.LDAPProtocolRequest
,ldaptor.protocols.pureber.BERSequence
-
modification
= None¶
-
object
= None¶
-
tag
= 70¶
-
-
class
ldaptor.protocols.pureldap.
LDAPModifyResponse
(resultCode=None, matchedDN=None, errorMessage=None, referral=None, serverSaslCreds=None, tag=None)[source]¶ Bases:
ldaptor.protocols.pureldap.LDAPResult
-
tag
= 71¶
-
-
class
ldaptor.protocols.pureldap.
LDAPPasswordModifyRequest
(requestName=None, userIdentity=None, oldPasswd=None, newPasswd=None, tag=None)[source]¶ Bases:
ldaptor.protocols.pureldap.LDAPExtendedRequest
-
oid
= '1.3.6.1.4.1.4203.1.11.1'¶
-
-
class
ldaptor.protocols.pureldap.
LDAPPasswordModifyRequest_newPasswd
(value=None, tag=None)[source]¶ Bases:
ldaptor.protocols.pureber.BEROctetString
-
tag
= 130¶
-
-
class
ldaptor.protocols.pureldap.
LDAPPasswordModifyRequest_oldPasswd
(value=None, tag=None)[source]¶ Bases:
ldaptor.protocols.pureber.BEROctetString
-
tag
= 129¶
-
-
class
ldaptor.protocols.pureldap.
LDAPPasswordModifyRequest_userIdentity
(value=None, tag=None)[source]¶ Bases:
ldaptor.protocols.pureber.BEROctetString
-
tag
= 128¶
-
-
class
ldaptor.protocols.pureldap.
LDAPProtocolRequest
[source]¶ Bases:
ldaptor.protocols.pureldap.LDAPProtocolOp
-
needs_answer
= 1¶
-
-
class
ldaptor.protocols.pureldap.
LDAPReferral
(value=None, tag=None)[source]¶ Bases:
ldaptor.protocols.pureber.BERSequence
-
tag
= 131¶
-
-
class
ldaptor.protocols.pureldap.
LDAPResponse
(value=None, tag=None)[source]¶ Bases:
ldaptor.protocols.pureber.BEROctetString
-
tag
= 139¶
-
-
class
ldaptor.protocols.pureldap.
LDAPResponseName
(value=None, tag=None)[source]¶ Bases:
ldaptor.protocols.pureldap.LDAPOID
-
tag
= 138¶
-
-
class
ldaptor.protocols.pureldap.
LDAPResult
(resultCode=None, matchedDN=None, errorMessage=None, referral=None, serverSaslCreds=None, tag=None)[source]¶ Bases:
ldaptor.protocols.pureldap.LDAPProtocolResponse
,ldaptor.protocols.pureber.BERSequence
-
class
ldaptor.protocols.pureldap.
LDAPSearchRequest
(baseObject=None, scope=None, derefAliases=None, sizeLimit=None, timeLimit=None, typesOnly=None, filter=None, attributes=None, tag=None)[source]¶ Bases:
ldaptor.protocols.pureldap.LDAPProtocolRequest
,ldaptor.protocols.pureber.BERSequence
-
attributes
= []¶
-
baseObject
= ''¶
-
derefAliases
= 0¶
-
filter
= LDAPFilter_present(value='objectClass')¶
-
scope
= 2¶
-
sizeLimit
= 0¶
-
tag
= 67¶
-
timeLimit
= 0¶
-
typesOnly
= 0¶
-
-
class
ldaptor.protocols.pureldap.
LDAPSearchResultDone
(resultCode=None, matchedDN=None, errorMessage=None, referral=None, serverSaslCreds=None, tag=None)[source]¶ Bases:
ldaptor.protocols.pureldap.LDAPResult
-
tag
= 69¶
-
-
class
ldaptor.protocols.pureldap.
LDAPSearchResultEntry
(objectName, attributes, tag=None)[source]¶ Bases:
ldaptor.protocols.pureldap.LDAPProtocolResponse
,ldaptor.protocols.pureber.BERSequence
-
tag
= 68¶
-
-
class
ldaptor.protocols.pureldap.
LDAPSearchResultReference
[source]¶ Bases:
ldaptor.protocols.pureldap.LDAPProtocolResponse
-
tag
= 83¶
-
-
class
ldaptor.protocols.pureldap.
LDAPStartTLSRequest
(requestName=None, tag=None)[source]¶ Bases:
ldaptor.protocols.pureldap.LDAPExtendedRequest
Request to start Transport Layer Security. See RFC 2830 for details.
-
oid
= '1.3.6.1.4.1.1466.20037'¶
-
-
class
ldaptor.protocols.pureldap.
LDAPStartTLSResponse
(resultCode=None, matchedDN=None, errorMessage=None, referral=None, serverSaslCreds=None, responseName=None, response=None, tag=None)[source]¶ Bases:
ldaptor.protocols.pureldap.LDAPExtendedResponse
Response to start Transport Layer Security. See RFC 4511 section 4.14.2 for details.
-
oid
= '1.3.6.1.4.1.1466.20037'¶
-
-
class
ldaptor.protocols.pureldap.
LDAPUnbindRequest
(*args, **kwargs)[source]¶ Bases:
ldaptor.protocols.pureldap.LDAPProtocolRequest
,ldaptor.protocols.pureber.BERNull
-
needs_answer
= 0¶
-
tag
= 66¶
-
ldaptor.samba package¶
-
ldaptor.samba.smbpassword.
lmhash
(password='')¶ Generates lanman password hash for a given password.
Note that the author thinks LanMan hashes should be banished from the face of the earth.
Submodules¶
ldaptor.attributeset module¶
ldaptor.checkers module¶
ldaptor.compat module¶
-
ldaptor.compat.
callable
(object) → bool¶ Return whether the object is callable (i.e., some kind of function). Note that classes are callable, as are instances with a __call__() method.
-
ldaptor.compat.
base_string_types
¶ alias of
basestring
-
class
ldaptor.compat.
unicode
(object='') → unicode object¶ Bases:
basestring
unicode(string[, encoding[, errors]]) -> unicode object
Create a new Unicode object from the given encoded string. encoding defaults to the current default string encoding. errors can be ‘strict’, ‘replace’ or ‘ignore’ and defaults to ‘strict’.
-
capitalize
() → unicode¶ Return a capitalized version of S, i.e. make the first character have upper case and the rest lower case.
-
center
(width[, fillchar]) → unicode¶ Return S centered in a Unicode string of length width. Padding is done using the specified fill character (default is a space)
-
count
(sub[, start[, end]]) → int¶ Return the number of non-overlapping occurrences of substring sub in Unicode string S[start:end]. Optional arguments start and end are interpreted as in slice notation.
-
decode
([encoding[, errors]]) → string or unicode¶ Decodes S using the codec registered for encoding. encoding defaults to the default encoding. errors may be given to set a different error handling scheme. Default is ‘strict’ meaning that encoding errors raise a UnicodeDecodeError. Other possible values are ‘ignore’ and ‘replace’ as well as any other name registered with codecs.register_error that is able to handle UnicodeDecodeErrors.
-
encode
([encoding[, errors]]) → string or unicode¶ Encodes S using the codec registered for encoding. encoding defaults to the default encoding. errors may be given to set a different error handling scheme. Default is ‘strict’ meaning that encoding errors raise a UnicodeEncodeError. Other possible values are ‘ignore’, ‘replace’ and ‘xmlcharrefreplace’ as well as any other name registered with codecs.register_error that can handle UnicodeEncodeErrors.
-
endswith
(suffix[, start[, end]]) → bool¶ Return True if S ends with the specified suffix, False otherwise. With optional start, test S beginning at that position. With optional end, stop comparing S at that position. suffix can also be a tuple of strings to try.
-
expandtabs
([tabsize]) → unicode¶ Return a copy of S where all tab characters are expanded using spaces. If tabsize is not given, a tab size of 8 characters is assumed.
-
find
(sub[, start[, end]]) → int¶ Return the lowest index in S where substring sub is found, such that sub is contained within S[start:end]. Optional arguments start and end are interpreted as in slice notation.
Return -1 on failure.
-
format
(*args, **kwargs) → unicode¶ Return a formatted version of S, using substitutions from args and kwargs. The substitutions are identified by braces (‘{‘ and ‘}’).
-
index
(sub[, start[, end]]) → int¶ Like S.find() but raise ValueError when the substring is not found.
-
isalnum
() → bool¶ Return True if all characters in S are alphanumeric and there is at least one character in S, False otherwise.
-
isalpha
() → bool¶ Return True if all characters in S are alphabetic and there is at least one character in S, False otherwise.
-
isdecimal
() → bool¶ Return True if there are only decimal characters in S, False otherwise.
-
isdigit
() → bool¶ Return True if all characters in S are digits and there is at least one character in S, False otherwise.
-
islower
() → bool¶ Return True if all cased characters in S are lowercase and there is at least one cased character in S, False otherwise.
-
isnumeric
() → bool¶ Return True if there are only numeric characters in S, False otherwise.
-
isspace
() → bool¶ Return True if all characters in S are whitespace and there is at least one character in S, False otherwise.
-
istitle
() → bool¶ Return True if S is a titlecased string and there is at least one character in S, i.e. upper- and titlecase characters may only follow uncased characters and lowercase characters only cased ones. Return False otherwise.
-
isupper
() → bool¶ Return True if all cased characters in S are uppercase and there is at least one cased character in S, False otherwise.
-
join
(iterable) → unicode¶ Return a string which is the concatenation of the strings in the iterable. The separator between elements is S.
-
ljust
(width[, fillchar]) → int¶ Return S left-justified in a Unicode string of length width. Padding is done using the specified fill character (default is a space).
-
lower
() → unicode¶ Return a copy of the string S converted to lowercase.
-
lstrip
([chars]) → unicode¶ Return a copy of the string S with leading whitespace removed. If chars is given and not None, remove characters in chars instead. If chars is a str, it will be converted to unicode before stripping
-
partition
(sep) -> (head, sep, tail)¶ Search for the separator sep in S, and return the part before it, the separator itself, and the part after it. If the separator is not found, return S and two empty strings.
-
replace
(old, new[, count]) → unicode¶ Return a copy of S with all occurrences of substring old replaced by new. If the optional argument count is given, only the first count occurrences are replaced.
-
rfind
(sub[, start[, end]]) → int¶ Return the highest index in S where substring sub is found, such that sub is contained within S[start:end]. Optional arguments start and end are interpreted as in slice notation.
Return -1 on failure.
-
rindex
(sub[, start[, end]]) → int¶ Like S.rfind() but raise ValueError when the substring is not found.
-
rjust
(width[, fillchar]) → unicode¶ Return S right-justified in a Unicode string of length width. Padding is done using the specified fill character (default is a space).
-
rpartition
(sep) -> (head, sep, tail)¶ Search for the separator sep in S, starting at the end of S, and return the part before it, the separator itself, and the part after it. If the separator is not found, return two empty strings and S.
-
rsplit
([sep[, maxsplit]]) → list of strings¶ Return a list of the words in S, using sep as the delimiter string, starting at the end of the string and working to the front. If maxsplit is given, at most maxsplit splits are done. If sep is not specified, any whitespace string is a separator.
-
rstrip
([chars]) → unicode¶ Return a copy of the string S with trailing whitespace removed. If chars is given and not None, remove characters in chars instead. If chars is a str, it will be converted to unicode before stripping
-
split
([sep[, maxsplit]]) → list of strings¶ Return a list of the words in S, using sep as the delimiter string. If maxsplit is given, at most maxsplit splits are done. If sep is not specified or is None, any whitespace string is a separator and empty strings are removed from the result.
-
splitlines
(keepends=False) → list of strings¶ Return a list of the lines in S, breaking at line boundaries. Line breaks are not included in the resulting list unless keepends is given and true.
-
startswith
(prefix[, start[, end]]) → bool¶ Return True if S starts with the specified prefix, False otherwise. With optional start, test S beginning at that position. With optional end, stop comparing S at that position. prefix can also be a tuple of strings to try.
-
strip
([chars]) → unicode¶ Return a copy of the string S with leading and trailing whitespace removed. If chars is given and not None, remove characters in chars instead. If chars is a str, it will be converted to unicode before stripping
-
swapcase
() → unicode¶ Return a copy of S with uppercase characters converted to lowercase and vice versa.
-
title
() → unicode¶ Return a titlecased version of S, i.e. words start with title case characters, all remaining cased characters have lower case.
-
translate
(table) → unicode¶ Return a copy of the string S, where all characters have been mapped through the given translation table, which must be a mapping of Unicode ordinals to Unicode ordinals, Unicode strings or None. Unmapped characters are left untouched. Characters mapped to None are deleted.
-
upper
() → unicode¶ Return a copy of S converted to uppercase.
-
zfill
(width) → unicode¶ Pad a numeric string S with zeros on the left, to fill a field of the specified width. The string S is never truncated.
-
-
ldaptor.compat.
bytes
¶ alias of
str
-
ldaptor.compat.
join_unicode
()¶ S.join(iterable) -> unicode
Return a string which is the concatenation of the strings in the iterable. The separator between elements is S.
-
ldaptor.compat.
join_bytes
()¶ S.join(iterable) -> string
Return a string which is the concatenation of the strings in the iterable. The separator between elements is S.
-
ldaptor.compat.
join_byte_elems
()¶ S.join(iterable) -> string
Return a string which is the concatenation of the strings in the iterable. The separator between elements is S.
-
ldaptor.compat.
byte_elem_value
()¶ ord(c) -> integer
Return the integer ordinal of a one-character string.
-
ldaptor.compat.
irange
¶ alias of
xrange
-
class
ldaptor.compat.
imap
¶ Bases:
object
imap(func, *iterables) –> imap object
Make an iterator that computes the function using arguments from each of the iterables. Like map() except that it returns an iterator instead of a list and that it stops when the shortest iterable is exhausted instead of filling in None for shorter iterables.
-
next
¶
-
-
ldaptor.compat.
lmap
()¶ map(function, sequence[, sequence, ...]) -> list
Return a list of the results of applying the function to the items of the argument sequence(s). If more than one sequence is given, the function is called with an argument list consisting of the corresponding item of each sequence, substituting None for missing values when not all sequences have the same length. If the function is None, return a list of the items of the sequence (or a list of tuples if more than one sequence).
-
ldaptor.compat.
next
(iterator[, default])¶ Return the next item from the iterator. If default is given and the iterator is exhausted, it is returned instead of raising StopIteration.
ldaptor.config module¶
-
class
ldaptor.config.
LDAPConfig
(baseDN=None, serviceLocationOverrides=None, identityBaseDN=None, identitySearch=None)[source]¶ Bases:
object
-
baseDN
= None¶
-
identityBaseDN
= None¶
-
identitySearch
= None¶
-
ldaptor.delta module¶
Changes to the content of one single LDAP entry.
(This means these do not belong here: adding or deleting of entries, changing of location in tree)
-
class
ldaptor.delta.
Add
(key, *a, **kw)[source]¶ Bases:
ldaptor.delta.Modification
-
class
ldaptor.delta.
AddOp
(entry)[source]¶ Bases:
ldaptor.delta.Operation
-
class
ldaptor.delta.
Delete
(key, *a, **kw)[source]¶ Bases:
ldaptor.delta.Modification
-
class
ldaptor.delta.
DeleteOp
(dn)[source]¶ Bases:
ldaptor.delta.Operation
-
class
ldaptor.delta.
ModifyOp
(dn, modifications=[])[source]¶ Bases:
ldaptor.delta.Operation
ldaptor.dns module¶
DNS-related utilities.
ldaptor.entry module¶
-
class
ldaptor.entry.
BaseLDAPEntry
(dn, attributes={})[source]¶ Bases:
object
-
diff
(other)[source]¶ Compute differences between this and another LDAP entry.
@param other: An LDAPEntry to compare to.
@return: None if equal, otherwise a ModifyOp that would make this entry look like other.
-
dn
= None¶
-
-
class
ldaptor.entry.
EditableLDAPEntry
(dn, attributes={})[source]¶ Bases:
ldaptor.entry.BaseLDAPEntry
ldaptor.entryhelpers module¶
ldaptor.generate_password module¶
ldaptor.inmemory module¶
-
class
ldaptor.inmemory.
InMemoryLDIFProtocol
[source]¶ Bases:
ldaptor.protocols.ldap.ldifprotocol.LDIF
Receive LDIF data and gather results into an ReadOnlyInMemoryLDAPEntry.
You can override lookupFailed and addFailed to provide smarter error handling. They are called as Deferred errbacks; returning the reason causes error to pass onward and abort the whole operation. Returning None from lookupFailed skips that entry, but continues loading.
When the full LDIF data has been read, the completed Deferred will trigger.
-
exception
ldaptor.inmemory.
LDAPCannotRemoveRootError
(message=None)[source]¶ Bases:
ldaptor.protocols.ldap.ldaperrors.LDAPNamingViolation
Cannot remove root of LDAP tree
-
class
ldaptor.inmemory.
ReadOnlyInMemoryLDAPEntry
(*a, **kw)[source]¶ Bases:
ldaptor.entry.EditableLDAPEntry
,ldaptor.entryhelpers.DiffTreeMixin
,ldaptor.entryhelpers.SubtreeFromChildrenMixin
,ldaptor.entryhelpers.MatchMixin
,ldaptor.entryhelpers.SearchByTreeWalkingMixin
ldaptor.insensitive module¶
ldaptor.interfaces module¶
ldaptor.ldapfilter module¶
ldaptor.ldiftree module¶
Manage LDAP data as a tree of LDIF files.
-
exception
ldaptor.ldiftree.
LDAPCannotRemoveRootError
(message=None)[source]¶ Bases:
ldaptor.protocols.ldap.ldaperrors.LDAPNamingViolation
Cannot remove root of LDAP tree
-
class
ldaptor.ldiftree.
LDIFTreeEntry
(path, dn=None, *a, **kw)[source]¶ Bases:
ldaptor.entry.EditableLDAPEntry
,ldaptor.entryhelpers.DiffTreeMixin
,ldaptor.entryhelpers.SubtreeFromChildrenMixin
,ldaptor.entryhelpers.MatchMixin
,ldaptor.entryhelpers.SearchByTreeWalkingMixin
-
exception
ldaptor.ldiftree.
LDIFTreeEntryContainsMultipleEntries
[source]¶ Bases:
exceptions.Exception
LDIFTree entry contains multiple LDIF entries.
-
exception
ldaptor.ldiftree.
LDIFTreeEntryContainsNoEntries
[source]¶ Bases:
exceptions.Exception
LDIFTree entry does not contain a valid LDIF entry.
-
exception
ldaptor.ldiftree.
LDIFTreeNoSuchObject
[source]¶ Bases:
exceptions.Exception
LDIFTree does not contain such entry.
ldaptor.md4 module¶
helper implementing insecure and obsolete md4 algorithm. used for NTHASH format, which is also insecure and broken, since it’s just md4(password)
implementated based on rfc at http://www.faqs.org/rfcs/rfc1320.html
ldaptor.numberalloc module¶
Find an available uidNumber/gidNumber/other similar number.
ldaptor.schema module¶
-
class
ldaptor.schema.
AttributeTypeDescription
(text)[source]¶ Bases:
ldaptor.schema.ASN1ParserThingie
ASN Syntax:
AttributeTypeDescription = "(" whsp numericoid whsp ; AttributeType identifier [ "NAME" qdescrs ] ; name used in AttributeType [ "DESC" qdstring ] ; description [ "OBSOLETE" whsp ] [ "SUP" woid ] ; derived from this other AttributeType [ "EQUALITY" woid ; Matching Rule name [ "ORDERING" woid ; Matching Rule name [ "SUBSTR" woid ] ; Matching Rule name [ "SYNTAX" whsp noidlen whsp ] ; see section 4.3 [ "SINGLE-VALUE" whsp ] ; default multi-valued [ "COLLECTIVE" whsp ] ; default not collective [ "NO-USER-MODIFICATION" whsp ]; default user modifiable [ "USAGE" whsp AttributeUsage ]; default userApplications whsp ")" AttributeUsage = "userApplications" / "directoryOperation" / "distributedOperation" / ; DSA-shared "dSAOperation" ; DSA-specific, value depends on server noidlen = numericoid [ "{" len "}" ] len = numericstring
-
class
ldaptor.schema.
MatchingRuleDescription
(text)[source]¶ Bases:
ldaptor.schema.ASN1ParserThingie
ASN Syntax:
MatchingRuleDescription = "(" whsp numericoid whsp ; MatchingRule identifier [ "NAME" qdescrs ] [ "DESC" qdstring ] [ "OBSOLETE" whsp ] "SYNTAX" numericoid whsp ")"
-
class
ldaptor.schema.
ObjectClassDescription
(text)[source]¶ Bases:
ldaptor.schema.ASN1ParserThingie
ASN Syntax:
d = "0" / "1" / "2" / "3" / "4" / "5" / "6" / "7" / "8" / "9" numericstring = 1*d numericoid = numericstring *( "." numericstring ) space = 1*" " whsp = [ space ] descr = keystring qdescr = whsp "'" descr "'" whsp qdescrlist = [ qdescr *( qdescr ) ] ; object descriptors used as schema element names qdescrs = qdescr / ( whsp "(" qdescrlist ")" whsp ) dstring = 1*utf8 qdstring = whsp "'" dstring "'" whsp descr = keystring oid = descr / numericoid woid = whsp oid whsp ; set of oids of either form oids = woid / ( "(" oidlist ")" ) ObjectClassDescription = "(" whsp numericoid whsp ; ObjectClass identifier [ "NAME" qdescrs ] [ "DESC" qdstring ] [ "OBSOLETE" whsp ] [ "SUP" oids ] ; Superior ObjectClasses [ ( "ABSTRACT" / "STRUCTURAL" / "AUXILIARY" ) whsp ] ; default structural [ "MUST" oids ] ; AttributeTypes [ "MAY" oids ] ; AttributeTypes whsp ")"
-
class
ldaptor.schema.
SyntaxDescription
(text)[source]¶ Bases:
ldaptor.schema.ASN1ParserThingie
ASN Syntax:
SyntaxDescription = "(" whsp numericoid whsp [ "DESC" qdstring ] whsp ")"
ldaptor.testutil module¶
Utilities for writing Twistedy unit tests and debugging.
-
class
ldaptor.testutil.
LDAPClientTestDriver
(*responses)[source]¶ A test driver that looks somewhat like a real LDAPClient.
Pass in a list of lists of LDAPProtocolResponses. For each sent LDAP message, the first item of said list is iterated through, and all the items are sent as responses to the callback. The sent LDAP messages are stored in self.sent, so you can assert that the sent messages are what they are supposed to be.
It is also possible to include a Failure instance instead of a list of LDAPProtocolResponses which will cause the errback to be called with the failure.
-
fakeUnbindResponse
= 'fake-unbind-by-LDAPClientTestDriver'¶
-
-
ldaptor.testutil.
createServer
(proto, *responses, **kw)[source]¶ Create an LDAP server for testing. :param proto: The server protocol factory (e.g. ProxyBase). :param responses: The responses to initialize the LDAPClientTestDrive. :param proto_args: Optional mapping passed as keyword args to protocol factory.
ldaptor.usage module¶
-
class
ldaptor.usage.
Options_base_optional
[source]¶ -
optParameters
= (('base', None, None, 'LDAP base dn'),)¶
-
-
class
ldaptor.usage.
Options_bind
[source]¶ -
optParameters
= (('binddn', None, None, 'use Distinguished Name to bind to the directory'), ('bind-auth-fd', None, None, 'read bind password from filedescriptor'))¶
-
-
class
ldaptor.usage.
Options_bind_mandatory
[source]¶ Bases:
ldaptor.usage.Options_bind
-
class
ldaptor.usage.
Options_scope
[source]¶ -
optParameters
= (('scope', None, 'sub', 'LDAP search scope (one of base, one, sub)'),)¶
-
Module contents¶
Ldaptor Cookbook¶
Ldaptor Cookbook¶
The following recipies demonstrate how to accomplish various LDAP-related tasks with Twisted and Ldaptor. Recipies are broken into categories for convenience.
LDAP Clients¶
The following recipies demonstrate asynchronous LDAP clients.
A Minimal Client Using Endpoints¶
While Ldaptor exposes helper classes to connect clients to the DIT, it is possible to use the Twisted endpoints API to connect an Ldaptor client to a server.
#! /usr/bin/env python
from ldaptor.protocols.ldap.ldapclient import LDAPClient
from ldaptor.protocols.ldap.ldapsyntax import LDAPEntry
from twisted.internet.defer import inlineCallbacks, returnValue
from twisted.internet.endpoints import clientFromString, connectProtocol
from twisted.internet.task import react
from twisted.python import log
from cStringIO import StringIO
import sys
@inlineCallbacks
def onConnect(clientProtocol):
o = LDAPEntry(clientProtocol, "dc=org")
resultList = yield o.search()
f = StringIO()
for result in resultList:
f.write(str(result))
f.write("\n")
log.msg("LDIF formatted results:\n{0}".format(f.getvalue()))
def onError(err, reactor):
if reactor.running:
log.err(err)
reactor.stop()
def main(reactor):
log.startLogging(sys.stdout)
endpoint_str = "tcp:host=localhost:port=8080"
e = clientFromString(reactor, endpoint_str)
d = connectProtocol(e, LDAPClient())
d.addCallback(onConnect)
d.addErrback(onError, reactor)
return d
react(main)
The twisted.internet.task.react()
function is perfect for running a
one-shot main() function. When main() is called, we create a client
endpoint from a string description and the reactor.
twisted.internet.endpoints.connectProtocol()
is used to make a
one-time connection to an LDAP directory listening on the local host, port 8080.
When the deferred returned from that function fires, the connection has
been established and the client protocol instance is passed to the
onConnect()
callback.
This callback uses inline deferreds to make the syntax more compact. We create
an ldaptor.protocols.ldap.ldapsyntax.LDAPEntry
with a DN matching
the root of the directory and call the asynchronous search()
method. The
result returned when the deferred fires is a list of LDAPEntry
objects.
When cast as strings, these entries are formatted as LDIF.
LDAP Proxies¶
An LDAP proxy sits between an LDAP client and an LDAP server. It accepts LDAP requests from the client and forwards them to the LDAP server. Responses from the server are then relayed back to the client.
Why is it Useful?¶
An LDAP proxy has many different uses:
- If a client does not natively support LDAP over SSL or StartTLS, a proxy can be run on the client host. The client can interact with the proxy which can use LDAPS or StartTLS when communicating with the backend service.
- When troubleshooting LDAP connections between LDAP clients and servers, it can be useful to determine what kinds of requests and responses are passing between the client and server. Sometimes, access to client or server logs is not available or not helpful. By logging the interactions at the proxy, one can gain insight into what requests are being made by the client and what responses the server makes.
- It may be desirable to provide limited access to an LDAP service. For example, it may be desirable to grant an application search access to an LDAP DIT, but any Modify, Add, or Delete operations are not allowed. A proxy can be configured to disable those particular LDAP operations.
- LDAP requests can be modified before sending them on to the LDAP server. For example, the base DN of search could be transparently modified based on the current BIND user.
- Similarly, LDAP responses from the server can be modified before sending them to the client. For example, search results could be populated with computed attributes, or a domain could be appended to any returned uid attribute.
- The proxy can be configured to connect to one of several LDAP servers (replicas). This can be an effective technique when a particular LDAP client library shows affinity for a particular host in an LDAP replica round-robin architecture. The client can be configured to always connect to the proxy, which in turn will distrbute the connections amongst the replicas.
Proxy Recipies¶
A logging LDAP proxy inspects the LDAP requests and responses and records them in a log.
#! /usr/bin/env python
from ldaptor.protocols import pureldap
from ldaptor.protocols.ldap.ldapclient import LDAPClient
from ldaptor.protocols.ldap.ldapconnector import connectToLDAPEndpoint
from ldaptor.protocols.ldap.proxybase import ProxyBase
from twisted.internet import defer, protocol, reactor
from twisted.python import log
from functools import partial
import sys
class LoggingProxy(ProxyBase):
"""
A simple example of using `ProxyBase` to log requests and responses.
"""
def handleProxiedResponse(self, response, request, controls):
"""
Log the representation of the responses received.
"""
log.msg("Request => " + repr(request))
log.msg("Response => " + repr(response))
return defer.succeed(response)
def ldapBindRequestRepr(self):
l=[]
l.append('version={0}'.format(self.version))
l.append('dn={0}'.format(repr(self.dn)))
l.append('auth=****')
if self.tag!=self.__class__.tag:
l.append('tag={0}'.format(self.tag))
l.append('sasl={0}'.format(repr(self.sasl)))
return self.__class__.__name__+'('+', '.join(l)+')'
pureldap.LDAPBindRequest.__repr__ = ldapBindRequestRepr
if __name__ == '__main__':
"""
Demonstration LDAP proxy; listens on localhost:10389 and
passes all requests to localhost:8080.
"""
log.startLogging(sys.stderr)
factory = protocol.ServerFactory()
proxiedEndpointStr = 'tcp:host=localhost:port=8080'
use_tls = False
clientConnector = partial(
connectToLDAPEndpoint,
reactor,
proxiedEndpointStr,
LDAPClient)
def buildProtocol():
proto = LoggingProxy()
proto.clientConnector = clientConnector
proto.use_tls = use_tls
return proto
factory.protocol = buildProtocol
reactor.listenTCP(10389, factory)
reactor.run()
The main idea in the above program is to subclass
ldaptor.protocols.ldap.proxybase.ProxyBase
and override its
handleProxiedResponse()
method.
The function ldapBindRequestRepr()
is used to patch the
__repr__()
magic method of the
ldaptor.protocols.pureldap.LDAPBindRequest
class. The
representation normally prints the BIND password, which is typically not what
you want.
The main program entry point starts logging and creates a generic server factory.
The proxied LDAP server is configured to run on the local host on port 8080.
The factory protocol is set to a function that takes no arguments and returns an
instance of our LoggingProxy
that has been configured with a
clientConnector callable. When this callable is invoked, it will return a
deferred that will fire with a LDAPClient
instance when a connection
to the proxied LDAP server is established. The Twisted reactor is then
configured to listen on TCP port 10389 and use the factory to create server
protocol instances to handle incoming connections.
The ProxyBase
class handles the typical LDAP protocol events but
provides convenient hooks for intercepting LDAP requests and responses. In
this proxy, we wait until we have a reponse and log both the request and the
response. in the case of a search request with multiple responses, the
request is repeatedly displayed with each response.
This program explicitly starts logging and the Twisted reactor loop. However, the twistd program can perform these tasks for you and allow you to configure options from the command line.
from ldaptor.protocols import pureldap
from ldaptor.protocols.ldap.ldapclient import LDAPClient
from ldaptor.protocols.ldap.ldapconnector import connectToLDAPEndpoint
from ldaptor.protocols.ldap.proxybase import ProxyBase
from twisted.application.service import Application, Service
from twisted.internet import defer, protocol, reactor
from twisted.internet.endpoints import serverFromString
from twisted.python import log
from functools import partial
class LoggingProxy(ProxyBase):
"""
A simple example of using `ProxyBase` to log requests and responses.
"""
def handleProxiedResponse(self, response, request, controls):
"""
Log the representation of the responses received.
"""
log.msg("Request => " + repr(request))
log.msg("Response => " + repr(response))
return defer.succeed(response)
def ldapBindRequestRepr(self):
l=[]
l.append('version={0}'.format(self.version))
l.append('dn={0}'.format(repr(self.dn)))
l.append('auth=****')
if self.tag!=self.__class__.tag:
l.append('tag={0}'.format(self.tag))
l.append('sasl={0}'.format(repr(self.sasl)))
return self.__class__.__name__+'('+', '.join(l)+')'
pureldap.LDAPBindRequest.__repr__ = ldapBindRequestRepr
class LoggingProxyService(Service):
endpointStr = "tcp:10389"
proxiedEndpointStr = 'tcp:host=localhost:port=8080'
def startService(self):
factory = protocol.ServerFactory()
use_tls = False
proxiedEndpointStr = 'tcp:host=localhost:port=8080'
clientConnector = partial(
connectToLDAPEndpoint,
reactor,
self.proxiedEndpointStr,
LDAPClient)
def buildProtocol():
proto = LoggingProxy()
proto.clientConnector = clientConnector
proto.use_tls = use_tls
return proto
factory.protocol = buildProtocol
ep = serverFromString(reactor, self.endpointStr)
d = ep.listen(factory)
d.addCallback(self.setListeningPort)
d.addErrback(log.err)
def setListeningPort(self, port):
self.port_ = port
def stopService(self):
# If there are asynchronous cleanup tasks that need to
# be performed, add deferreds for them to `async_tasks`.
async_tasks = []
if self.port_ is not None:
async_tasks.append(self.port_.stopListening())
if len(async_tasks) > 0:
return defer.DeferredList(async_tasks, consumeErrors=True)
application = Application("Logging LDAP Proxy")
service = LoggingProxyService()
service.setServiceParent(application)
This program is very similar to the previous one. However, this one is run with twistd:
$ twistd -ny loggingproxy.py
The twistd program looks for the global name application in the
script and runs all the services attached to it. We moved most of the startup
code from the if __name__ == ‘__main__’ block into the service’s
startService()
method. This method is called when our service
starts up. Conversely, stopService()
is called when the service is
about to shut down.
This improved example also makes use of endpoint strings. These strings are textual descriptions of client and server sockets on which our LDAP proxy server will connect and listen, respectively.
The advantage of endpoints is that you can read these strings from a configuration file and change how your server listens or how you client connects. Our example listens on a plain old TCP socket, but you could easilly switch to a TLS socket or a UNIX domain socket without having to change a line of code.
Listening on an endpoint is an asynchronous task, so we set a callback to record the listening port. When the service stops, we ask the port to stop listening.
LDAP Merger¶
A merger forwards search requests to multiple LDAP Servers, and returns the result entries of each successful response.
Usecase¶
You have multiple LDAP Servers, and you want to combine the search results of all of them. This can be the case if you have an application which needs extra users which are not inside the LDAP directory of your enterprise server, and it is not desired to store them in it. In this case you could use an internal LDAP server on the local filesystem (you can also do this with ldaptor, please look at the LDAP Servers section, File-System LDAP DIT), and combine this server with your general LDAP server.
Caveats¶
Be aware that it the merger is a read-only implementation: only BIND and SEARCH operations are supported. Beyond that, notice that when binding only the servers where the bind has been successful are delivering search results. So in order to retrieve results on all servers, the bind user must be available on all LDAP servers.
Usage¶
Store the python code in a file called ldap-merger.tac:
#! /usr/bin/env python
from twisted.application import service, internet
from twisted.internet import protocol
from ldaptor.config import LDAPConfig
from ldaptor.protocols.ldap.merger import MergedLDAPServer
application = service.Application("LDAP Merger")
configs = [LDAPConfig(serviceLocationOverrides={"": ('external', 389)}),
LDAPConfig(serviceLocationOverrides={"": ('localhost', 38942)})]
use_tls = [True, False]
factory = protocol.ServerFactory()
factory.protocol = lambda: MergedLDAPServer(configs, use_tls)
mergeService = internet.TCPServer(389, factory)
mergeService.setServiceParent(application)
We use two ldap servers: one listening on the host ‘’external’’ on the default port 389, and the other is a server running on localhost with port 38942. TLS is used for the connection to the external server. The merger itself listens on port 389.
- Run it with
- $ twistd -y ldap-merger.tac
LDAP Servers¶
An LDAP directory information tree (DIT) is a highly specialized database with entries arranged in a tree-like structure.
File-System LDAP DIT¶
A minimal LDAP DIT that stores entries in the local file system
First, a module that defines our DIT entries– schema.py
#-*-coding:utf-8-*-
COUNTRY = (
'dc=fr',
{
'objectClass': ['dcObject','country'],
'dc': ['fr'],
'description': ["French country 2 letters iso description"],
}
)
COMPANY = (
'dc=example',
{
'objectClass': ['dcObject','organization'],
'dc': ['example'],
'description': ["My organisation"],
'o': ["Example, Inc"],
}
)
PEOPLE = (
'ou=people',
{
'ou': ['people'],
'description': ['People from Example Inc'],
'objectclass': ['organizationalunit'],
}
)
USERS = [
('uid=yoen',
{
'objectClass': ['people', 'inetOrgPerson'],
'cn': ['Yoen Van der Weld'],
'sn': ['Van der Weld'],
'givenName': ['Yoen'],
'uid': ['yoen'],
'mail': ['/home/yoen/mailDir'],
'userPassword': ['secret']
}
),
('uid=esteban',
{
'objectClass': ['people', 'inetOrgPerson'],
'cn': ['Esteban Garcia Marquez'],
'sn': ['Garcia Marquez'],
'givenName': ['Esteban'],
'uid': ['esteban'],
'mail': ['/home/esteban/mailDir'],
'userPassword': ['secret2']
}
),
('uid=mohamed',
{
'objectClass': ['people', 'inetOrgPerson'],
'cn': ['Mohamed Al Ghâlib'],
'sn': ['Al Ghâlib'],
'givenName': ['mohamed'],
'uid': ['mohamed'],
'mail': ['/home/mohamed/mailDir'],
'userPassword': ['secret3']
}
),
]
Next, the server code– fsdit.py
#-*-coding:utf-8-*-
"""
Testing a simple ldaptor ldap server
Base on an example by Gaston TJEBBES aka "tonthon":
http://tonthon.blogspot.com/2011/02/ldaptor-ldap-with-twisted-server-side.html
"""
import tempfile, sys
from twisted.application import service, internet
from twisted.internet import reactor
from twisted.internet.protocol import ServerFactory
from twisted.python.components import registerAdapter
from twisted.python import log
from ldaptor.interfaces import IConnectedLDAPEntry
from ldaptor.protocols.ldap.ldapserver import LDAPServer
from ldaptor.ldiftree import LDIFTreeEntry
from schema import COUNTRY, COMPANY, PEOPLE, USERS
class Tree(object):
def __init__(self, path='/tmp'):
dirname = tempfile.mkdtemp('.ldap', 'test-server', '/tmp')
self.db = LDIFTreeEntry(dirname)
self.init_db()
def init_db(self):
"""
Add subtrees to the top entry
top->country->company->people
"""
country = self.db.addChild(COUNTRY[0], COUNTRY[1])
company = country.addChild(COMPANY[0], COMPANY[1])
people = company.addChild(PEOPLE[0], PEOPLE[1])
for user in USERS:
people.addChild(user[0], user[1])
class LDAPServerFactory(ServerFactory):
"""
Our Factory is meant to persistently store the ldap tree
"""
protocol = LDAPServer
def __init__(self, root):
self.root = root
def buildProtocol(self, addr):
proto = self.protocol()
proto.debug = self.debug
proto.factory = self
return proto
if __name__ == '__main__':
if len(sys.argv) == 2:
port = int(sys.argv[1])
else:
port = 8080
# First of all, to show logging info in stdout :
log.startLogging(sys.stderr)
# We initialize our tree
tree = Tree()
# When the ldap protocol handle the ldap tree,
# it retrieves it from the factory adapting
# the factory to the IConnectedLDAPEntry interface
# So we need to register an adapter for our factory
# to match the IConnectedLDAPEntry
registerAdapter(
lambda x: x.root,
LDAPServerFactory,
IConnectedLDAPEntry)
# Run it !!
factory = LDAPServerFactory(tree.db)
factory.debug = True
application = service.Application("ldaptor-server")
myService = service.IServiceCollection(application)
reactor.listenTCP(port, factory)
reactor.run()
Meta¶
Changelog¶
Release 16.0 (2016-06-07)¶
Features¶
- Make meta data introspectable
- Added proxybase.py, an LDAP proxy that is easier to hook into.
- When parsing LDAPControls, criticality may not exist while controlValue still does
- Requested attributes can also be passed as ‘*’ symbol
- Numerous small bug fixes.
- Additional documentation
- Updated Travis-CI, Tox and other bits for better coverage.
Release 14.0 (2014-10-31)¶
Ldaptor has a new version schema. As a first-party library we now follow Twisted’s example.
License¶
- Ldaptor’s original author Tommi Virtanen changed the license to the MIT (Expat) license.
- ldaptor.md4 has been replaced by a 3-clause BSD version.
API Changes¶
- Ldaptor client and server: None
- Everything having to do with webui and Nevow have been removed.
Features¶
- Travis CI is now used for continuous integration.
- Test coverage is now measured. We’re currently at around 75%.
- tox is used now to test ldaptor on all combinations of pypy, Python 2.6, Python 2.7 and Twisted versions from 10.0 until 14.0.
- A few ordering bugs that were exposed by that and are fixed now.
- ldaptor.protocols.pureldap.LDAPExtendedRequest now has additional tests.
- The new ldaptor.protocols.pureldap.LDAPAbandonRequest adds support for abandoning requests.
- ldaptor.protocols.pureldap.LDAPBindRequest has basic SASL support now. Higher-level APIs like ldapclient don’t expose it yet though.
Bugfixes¶
- ldaptor.protocols.ldap.ldapclient’s now uses log.msg for it’s debug listing instead of the non-Twisted log.debug.
- String literal exceptions have been replaced by real Exceptions.
- “bin/ldaptor-ldap2passwd –help” now does not throws an exception anymore (debian bug #526522).
- ldaptor.delta.Modification and ldaptor.protocols.ldap.ldapsyntax.PasswordSetAggregateError that are used for adding contacts now handle unicode arguments properly.
- ldaptor.protocols.pureldap.LDAPExtendedRequest’s constructor now handles STARTTLS in accordance to RFC2251 so the constructor of ldaptor.protocols.pureldap.LDAPStartTLSRequest doesn’t fail anymore.
- ldaptor.protocols.ldap.ldapserver.BaseLDAPServer now uses the correct exception module in dataReceived.
- ldaptor.protocols.ldap.ldaperrors.LDAPException: “Fix deprecated exception error”
- bin/ldaptor-find-server now imports dns from the correct twisted modules.
- bin/ldaptor-find-server now only prints SRV records.
- ldaptor.protocols.ldap.ldapsyntax.LDAPEntryWithClient now correctly propagates errors on search(). The test suite has been adapted appropriately.
- ldaptor.protocols.ldap.ldapconnector.LDAPConnector now supports specifying a local address when connecting to a server.
- The new ldaptor.protocols.pureldap.LDAPSearchResultReference now prevents ldaptor from choking on results containing SearchResultReference (usually from Active Directory servers). It is currently only a stub and silently ignored.
- hashlib and built-in set() are now used instead of deprecated modules.
Improved Documentation¶
- Added, updated and reworked documentation using Sphinx. Dia is required for converting diagrams to svg/png, this might change in the future.
- Dia is now invoked correctly for diagram generation in a headless environment.
- The documentation is now hosted on https://ldaptor.readthedocs.org/.
Prehistory¶
All versions up to and including 0.0.43 didn’t have a changelog.
Status and History¶
Ldaptor was created by Tommi Virtanen who developed it during the years 2001-2008. From 2007 and onwards mainly bug fixes were added, many contributed by Debian maintainers. Development picked back up in 2014 by Bret Curtis with Tommi’s consent and was migrated to Twisted where it is a first-party Twisted library. Ldaptor can be found here:
https://github.com/twisted/ldaptor
The LDAP client library functionality is in active use. It is stable and works very well.
Contributions¶
How to Contribute¶
Head over to: https://github.com/twisted/ldaptor and submit your bugs or feature requests. If you wish to contribute code, just fork it, make a branch and send us a pull request. We’ll review it, and push back if necessary.
Ldaptor generally follows the coding and documentation standards of the Twisted project.
Contributors¶
- Anton Gyllenberg
- Aren Sandersen
- Bret Curtis
- Carl Waldbieser
- Christopher Bartz
- David Strauss
- HawkOwl
- Hynek Schlawack
- Kenny MacDermid
- Michael Schlenker
- Stefan Andersson
- Tommi Virtanen