Skip to content

Commit

Permalink
Merge Michael's work from the CVS repository on SourceForge
Browse files Browse the repository at this point in the history
This includes changes from the 2.5.2 and (unfinished) 2.5.3 branches,
excluding those that do extensive code reformatting. The list
of those follows.
(Commit IDs correspond to 'cvs' tracking branch in pyldap.)

Changes left out:
b837b541bd6860dd5dee613055b2d1d4c08fa441 stripped trailing spaces from C source files
ef16f9f305b76c5930c79da412a8a984f3c7ed77 module ldapurl now almost PEP-8 compliant
6680752d8fe1186cf5a4f445216b498601091cab module ldif now almost PEP-8 compliant
5880eb5ecce58fc468266b4bbca61024f89c1650 PyBytes_ instead of PyString_ and PyInt_FromLong/PyLong_FromLong shim
2d423bd2fd039fab922481249f7f1e461c20d2b7 PEP-8 for ldap.cidict
5c11c368a3ced124a7837362553ad3265e0a086a announce more modules with PEP-8 compliance
637daad82e850a719cf8e68d56d172f8bc3634a5 PEP-8 for ldap.modlist
8692df7b740d8870121db9f67a82d18129f4dab7 PEP-8 for ldap.filter
ab130d9a357c6fda6731bae868b9f27515536f32 a bit of PEP-8 for ldap.dn
c4388b50894ef762031de153257417e13b3614ba a bit of PEP-8 for ldap.functions
fa1f5e4db416da7f2e2f6fc35ef71768bded0379 a bit of PEP-8 for ldap.__init__
feb1e57ca2523aa7a5af38932b89a66ac78f1dc8 ldap.ldapobject: PEP-8 and pylint
b5e0c3c5e9c3dcf306a5078d2181c26d77456195 ldap.ldapobject: wrapped all lines exceeding 100 chars
956c961d99d41e25cff7202df1f4c7d80828b1ea ldap.ldapobject split into module-package
13ae2115d13b155feb7a51f0cfd0e26ade19313d moved SimpleLDAPObject to separate sub-module ldap.ldapobject.simple
07c771aa77722b3958fe2158baa796c654baa81e added ldap.ldapobject.reconnect.__all__
f8d636ac24d1cd961b62470476e47b64cdf0bc89 added ldap.ldapobject.simple
f01e2a584e004052e6eff95e61b84b2c5a585556 cleanup up setup.py
9a7c52e0c9ebf9b12496afaeb17df2adef25ab7e correctly set -D in setup.py
37983e2fbbe7710d9ce30593c40cda89e5bc27fc do not use pprint, avoid filter()
c81418ed9a7c3263ae26c8c021980d2b47d01cdb import ... as
39903aad163e1c1328841c59be05c13739a258c1 announce changes in setup.py
73c357e92a5fe8191e230ecafeceddfd2301ad05 started 2.5.3
03cbc30c329e85a7d3cb327d5b85a7f43ffbdcc5 ldap.async: PEP-8 and pylint
e19d0c21ce3c198a7f342b1d35d4a0adf25eb8fc (cvs) ldap.schema.tokenizer: PEP-8 and pylint

From the first one (b837b54: stripped trailing spaces from C source files),
the code for adding _ldap.__version__ is kept.
  • Loading branch information
Petr Viktorin committed Nov 22, 2017
2 parents 6b1063e + 3141ce0 commit fc020d0
Show file tree
Hide file tree
Showing 45 changed files with 1,360 additions and 659 deletions.
31 changes: 31 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
@@ -1,3 +1,34 @@
----------------------------------------------------------------
Released 2.5.2 2017-11-20

Changes since 2.5.1:

Modules/
* PyBytes_ instead of PyString_ and added PyInt_FromLong compat macro
* moved code from version.c to ldapmodule.c
* removed obsolete back-ward compability constants from common.h
* build checks whether LDAP_API_VERSION is OpenLDAP 2.4.x
* _ldap.__author__ and _ldap.__license__ also set from ldap.pkginfo
* assume C extension API for Python 2.7+

Lib/
* removed all dependencies on modules string and types
* removed use of .has_key()
* removed class ldap.ldapobject.NonblockingLDAPObject
* new global constant ldap.LIBLDAP_API_INFO
* right after importing _ldap there is a call into libldap to initialize it
* method .decodeControlValue() of SSSResponseControl and VLVResponseControl
does not set class attribute result_code anymore
* always use bytes() for UUID() constructor in ldap.syncrepl
* module ldif now uses functions b64encode() and b64decode()
* fixed pickling and restoring of ReconnectLDAPObject

Tests/
* scripts do not directly call SlapdTestCase.setUpClass() anymore
* added LDIF test with folded, base64-encoded attribute
* added more tests for sub-module ldap.dn
* added tests for ldap.syncrepl (thanks to Karl Kornel)

----------------------------------------------------------------
Released 2.5.1 2017-11-12

Expand Down
3 changes: 0 additions & 3 deletions Demo/Lib/ldap/async/ldifwriter.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@
This example translates the naming context of data read from
input, sanitizes some attributes, maps/removes object classes,
maps/removes attributes., etc. It's far from being complete though.
Python compability note:
Tested on Python 2.0+, should run on Python 1.5.x.
"""

import sys,ldap,ldap.async
Expand Down
3 changes: 0 additions & 3 deletions Demo/Lib/ldap/async/sizelimit.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@
This example translates the naming context of data read from
input, sanitizes some attributes, maps/removes object classes,
maps/removes attributes., etc. It's far from being complete though.
Python compability note:
Tested on Python 2.0+, should run on Python 1.5.x.
"""

import sys,ldap,ldap.async
Expand Down
3 changes: 0 additions & 3 deletions Demo/Lib/ldif/ldifcopy.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@
This example translates the naming context of data read from
input, sanitizes some attributes, maps/removes object classes,
maps/removes attributes., etc. It's far from being complete though.
Python compability note:
Tested on Python 2.0+, should run on Python 1.5.x.
"""

import sys,ldif
Expand Down
110 changes: 58 additions & 52 deletions Demo/pyasn1/syncrepl.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,14 @@
Notes:
The bound user needs read access to the attributes entryDN and entryCSN.
This needs the following software:
Python
pyasn1 0.1.4+
pyasn1-modules
python-ldap 2.4.10+
"""

# Import modules from Python standard lib
import shelve,signal,time,sys,logging
import logging
import shelve
import signal
import sys
import time

# Import the python-ldap modules
import ldap
Expand All @@ -25,28 +23,34 @@
from ldap.ldapobject import ReconnectLDAPObject
from ldap.syncrepl import SyncreplConsumer

logger = logging.getLogger('syncrepl')
logger.setLevel(logging.DEBUG)
logger.addHandler(logging.StreamHandler())

# Global state
watcher_running = True
ldap_connection = False


class SyncReplConsumer(ReconnectLDAPObject, SyncreplConsumer):
class SyncReplClient(ReconnectLDAPObject, SyncreplConsumer):
"""
Syncrepl Consumer interface
Syncrepl Consumer Client
"""

def __init__(self, db_path, *args, **kwargs):
# Initialise the LDAP Connection first
ldap.ldapobject.ReconnectLDAPObject.__init__(self, *args, **kwargs)
# Now prepare the data store
self.__data = shelve.open(db_path, 'c')
if db_path:
self.__data = shelve.open(db_path, 'c')
else:
self.__data = dict()
# We need this for later internal use
self.__presentUUIDs = dict()

def close_db(self):
# Close the data store properly to avoid corruption
self.__data.close()
# Close the data store properly to avoid corruption
self.__data.close()

def syncrepl_get_cookie(self):
if 'cookie' in self.__data:
Expand All @@ -55,7 +59,8 @@ def syncrepl_get_cookie(self):
def syncrepl_set_cookie(self,cookie):
self.__data['cookie'] = cookie

def syncrepl_entry(self,dn,attributes,uuid):
def syncrepl_entry(self, dn, attributes, uuid):
logger.debug('dn=%r attributes=%r uuid=%r', dn, attributes, uuid)
# First we determine the type of change we have here
# (and store away the previous data for later if needed)
previous_attributes = dict()
Expand All @@ -69,18 +74,18 @@ def syncrepl_entry(self,dn,attributes,uuid):
attributes['dn'] = dn
self.__data[uuid] = attributes
# Debugging
print 'Detected', change_type, 'of entry:', dn
logger.debug('Detected %s of entry %r', change_type, dn)
# If we have a cookie then this is not our first time being run,
# so it must be a change
if 'ldap_cookie' in self.__data:
self.perform_application_sync(dn, attributes, previous_attributes)
self.perform_application_sync(dn, attributes, previous_attributes)

def syncrepl_delete(self,uuids):
# Make sure we know about the UUID being deleted, just in case...
uuids = [uuid for uuid in uuids if uuid in self.__data]
# Delete all the UUID values we know of
for uuid in uuids:
print 'Detected deletion of entry:', self.__data[uuid]['dn']
logger.debug('Detected deletion of entry %r', self.__data[uuid]['dn'])
del self.__data[uuid]

def syncrepl_present(self,uuids,refreshDeletes=False):
Expand All @@ -105,78 +110,80 @@ def syncrepl_present(self,uuids,refreshDeletes=False):
self.__presentUUIDs[uuid] = True

def syncrepl_refreshdone(self):
print 'Initial synchronization is now done, persist phase begins'
logger.info('Initial synchronization is now done, persist phase begins')

def perform_application_sync(self,dn,attributes,previous_attributes):
print 'Performing application sync for:', dn
logger.info('Performing application sync for %r', dn)
return True


# Shutdown handler
def commenceShutdown(signum, stack):
# Declare the needed global variables
global watcher_running, ldap_connection
print 'Shutting down!'
logger.warn('Shutting down!')

# We are no longer running
watcher_running = False

# Tear down the server connection
if( ldap_connection ):
ldap_connection.close_db()
ldap_connection.unbind_s()
del ldap_connection
if ldap_connection:
ldap_connection.close_db()
ldap_connection.unbind_s()
del ldap_connection

# Shutdown
sys.exit(0)

# Time to actually begin execution
# Install our signal handlers
signal.signal(signal.SIGTERM,commenceShutdown)
signal.signal(signal.SIGINT,commenceShutdown)
signal.signal(signal.SIGTERM, commenceShutdown)
signal.signal(signal.SIGINT, commenceShutdown)


try:
ldap_url = ldapurl.LDAPUrl(sys.argv[1])
database_path = sys.argv[2]
ldap_url = ldapurl.LDAPUrl(sys.argv[1])
database_path = sys.argv[2]
except IndexError,e:
print 'Usage:'
print sys.argv[0], '<LDAP URL> <pathname of database>'
print sys.argv[0], '\'ldap://127.0.0.1/cn=users,dc=test'\
'?*'\
'?sub'\
'?(objectClass=*)'\
'?bindname=uid=admin%2ccn=users%2cdc=test,'\
'X-BINDPW=password\' db.shelve'
print (
'Usage:\n'
'{script_name} <LDAP URL> <pathname of database>\n'
'{script_name} "ldap://127.0.0.1/cn=users,dc=test'
'?*'
'?sub'
'?(objectClass=*)'
'?bindname=uid=admin%2ccn=users%2cdc=test,'
'X-BINDPW=password" db.shelve'
).format(script_name=sys.argv[0])
sys.exit(1)
except ValueError,e:
print 'Error parsing command-line arguments:',str(e)
sys.exit(1)
print 'Error parsing command-line arguments:', str(e)
sys.exit(1)

while watcher_running:
print 'Connecting to LDAP server now...'
logger.info('Connecting to %s now...', ldap_url.initializeUrl())
# Prepare the LDAP server connection (triggers the connection as well)
ldap_connection = SyncReplConsumer(database_path, ldap_url.initializeUrl())
ldap_connection = SyncReplClient(database_path, ldap_url.initializeUrl())

# Now we login to the LDAP server
try:
ldap_connection.simple_bind_s(ldap_url.who, ldap_url.cred)
except ldap.INVALID_CREDENTIALS, e:
print 'Login to LDAP server failed: ', str(e)
except ldap.INVALID_CREDENTIALS, err:
logger.error('Login to LDAP server failed: %s', err)
sys.exit(1)
except ldap.SERVER_DOWN:
print 'LDAP server is down, going to retry.'
logger.warn('LDAP server is down, going to retry.')
time.sleep(5)
continue

# Commence the syncing
print 'Commencing sync process'
logger.debug('Commencing sync process')
ldap_search = ldap_connection.syncrepl_search(
ldap_url.dn or '',
ldap_url.scope or ldap.SCOPE_SUBTREE,
mode = 'refreshAndPersist',
attrlist=ldap_url.attrs,
filterstr = ldap_url.filterstr or '(objectClass=*)'
ldap_url.dn or '',
ldap_url.scope or ldap.SCOPE_SUBTREE,
mode = 'refreshAndPersist',
attrlist=ldap_url.attrs,
filterstr = ldap_url.filterstr or '(objectClass=*)'
)

try:
Expand All @@ -185,10 +192,9 @@ def commenceShutdown(signum, stack):
except KeyboardInterrupt:
# User asked to exit
commenceShutdown(None, None)
pass
except Exception, e:
except Exception, err:
# Handle any exception
if watcher_running:
print 'Encountered a problem, going to retry. Error:', str(e)
logger.exception('Unhandled exception, going to retry: %s', err)
logger.info('Going to retry after 5 secs')
time.sleep(5)
pass
3 changes: 0 additions & 3 deletions Demo/resiter.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@
written by Michael Stroeder <michael@stroeder.com>
See http://www.python-ldap.org for details.
Python compability note:
Requires Python 2.3+
"""

import ldap,ldap.resiter
Expand Down
5 changes: 2 additions & 3 deletions Demo/simplebrowse.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
#

import ldap
import string
from traceback import print_exc

url = "ldap://ldap.openldap.org/"
Expand Down Expand Up @@ -71,8 +70,8 @@
if arg == '-':
lastdn,dn = dn,lastdn
elif arg == '..':
dn = string.join(ldap.explode_dn(dn)[1:], ",")
dn = string.strip(dn)
dn = ldap.explode_dn(dn)[1:].join(",")
dn = dn.strip()
else:
try:
i = int(arg)
Expand Down
2 changes: 1 addition & 1 deletion Doc/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
# The short X.Y version.
version = '2.5'
# The full version, including alpha/beta/rc tags.
release = '2.5.1.0'
release = '2.5.2.0'

# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
Expand Down
24 changes: 12 additions & 12 deletions Doc/ldap-dn.rst
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ The :mod:`ldap.dn` module defines the following functions:
function :func:`escape_dn_chars`.


.. function:: explode_dn(dn [, notypes=0[, flags=0]]) -> list
.. function:: explode_dn(dn [, notypes=False[, flags=0]]) -> list

This function takes *dn* and breaks it up into its component parts. Each part
is known as an RDN (Relative Distinguished Name). The optional *notypes*
Expand All @@ -60,7 +60,7 @@ The :mod:`ldap.dn` module defines the following functions:
deprecated.


.. function:: explode_rdn(rdn [, notypes=0[, flags=0]]) -> list
.. function:: explode_rdn(rdn [, notypes=False[, flags=0]]) -> list

This function takes a (multi-valued) *rdn* and breaks it up into a list of
characteristic attributes. The optional *notypes* parameter is used to specify
Expand All @@ -85,26 +85,26 @@ Splitting a LDAPv3 DN to AVA level. Note that both examples have the same result
but in the first example the non-ASCII chars are passed as is (byte buffer string)
whereas in the second example the hex-encoded DN representation are passed to the function.

>>> ldap.dn.str2dn('cn=Michael Str\xc3\xb6der,dc=stroeder,dc=com',flags=ldap.DN_FORMAT_LDAPV3)
[[('cn', 'Michael Str\xc3\xb6der', 4)], [('dc', 'stroeder', 1)], [('dc', 'com', 1)]]
>>> ldap.dn.str2dn('cn=Michael Str\C3\B6der,dc=stroeder,dc=com',flags=ldap.DN_FORMAT_LDAPV3)
[[('cn', 'Michael Str\xc3\xb6der', 4)], [('dc', 'stroeder', 1)], [('dc', 'com', 1)]]
>>> ldap.dn.str2dn('cn=Michael Str\xc3\xb6der,dc=example,dc=com',flags=ldap.DN_FORMAT_LDAPV3)
[[('cn', 'Michael Str\xc3\xb6der', 4)], [('dc', 'example', 1)], [('dc', 'com', 1)]]
>>> ldap.dn.str2dn('cn=Michael Str\C3\B6der,dc=example,dc=com',flags=ldap.DN_FORMAT_LDAPV3)
[[('cn', 'Michael Str\xc3\xb6der', 4)], [('dc', 'example', 1)], [('dc', 'com', 1)]]


Splitting a LDAPv2 DN into RDN parts:

>>> ldap.dn.explode_dn('cn=Michael Stroeder;dc=stroeder;dc=com',flags=ldap.DN_FORMAT_LDAPV2)
['cn=Michael Stroeder', 'dc=stroeder', 'dc=com']
>>> ldap.dn.explode_dn('cn=John Doe;dc=example;dc=com',flags=ldap.DN_FORMAT_LDAPV2)
['cn=John Doe', 'dc=example', 'dc=com']


Splitting a multi-valued RDN:

>>> ldap.dn.explode_rdn('cn=Michael Stroeder+mail=michael@stroeder.com',flags=ldap.DN_FORMAT_LDAPV2)
['cn=Michael Stroeder', 'mail=michael@stroeder.com']
>>> ldap.dn.explode_rdn('cn=John Doe+mail=john.doe@example.com',flags=ldap.DN_FORMAT_LDAPV2)
['cn=John Doe', 'mail=john.doe@example.com']

Splitting a LDAPv3 DN with a multi-valued RDN into its AVA parts:


>>> ldap.dn.str2dn('cn=Michael Stroeder+mail=michael@stroeder.com,dc=stroeder,dc=com')
[[('cn', 'Michael Stroeder', 1), ('mail', 'michael@stroeder.com', 1)], [('dc', 'stroeder', 1)], [('dc', 'com', 1)]]
>>> ldap.dn.str2dn('cn=John Doe+mail=john.doe@example.com,dc=example,dc=com')
[[('cn', 'John Doe', 1), ('mail', 'john.doe@example.com', 1)], [('dc', 'example', 1)], [('dc', 'com', 1)]]

2 changes: 2 additions & 0 deletions Lib/ldap/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
assert _ldap.__version__==__version__, \
ImportError('ldap %s and _ldap %s version mismatch!' % (__version__,_ldap.__version__))
from _ldap import *
# call into libldap to initialize it right now
LIBLDAP_API_INFO = _ldap.get_option(_ldap.OPT_API_INFO)

OPT_NAMES_DICT = {}
for k,v in vars(_ldap).items():
Expand Down
Loading

0 comments on commit fc020d0

Please sign in to comment.