Skip to content

Commit

Permalink
Merge Python 3 porting (and infrastructure improvements) from pyldap
Browse files Browse the repository at this point in the history
The full history of the pyldap fork can be found at https://github.com/pyldap/pyldap/
  • Loading branch information
Petr Viktorin committed Nov 24, 2017
2 parents fc020d0 + 3138957 commit 4c9c526
Show file tree
Hide file tree
Showing 74 changed files with 1,478 additions and 586 deletions.
17 changes: 17 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@

# Auto-generated
.*.swp
*.pyc
__pycache__/
.tox

# shared libs installed by 'setup.py test'
/Lib/*.so*
/Lib/*.dylib
/Lib/*.pyd

# Build related
*.egg-info
build/
dist/
PKG-INFO
25 changes: 25 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
language: python

python:
- '2.7'
- '3.3'
- '3.4'
- '3.5'
- '3.6'
# Note: when updating Python versions, also change setup.py and tox.ini

sudo: false

cache: pip

addons:
apt:
packages:
- ldap-utils
- slapd

install:
- pip install "pip>=7.1.0"
- pip install tox-travis tox

script: tox
75 changes: 42 additions & 33 deletions CHANGES
Original file line number Diff line number Diff line change
@@ -1,47 +1,30 @@
----------------------------------------------------------------
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
Released 3.0.0 xxxx-xx-xx

Changes since 2.4.45:

Mandatory prerequisites:
- Python 2.7.x
- Python 2.7.x or 3.3+
- pyasn1 0.3.7+ and pyasn1_modules 0.1.5+

Python 3 support is merged from the pyldap fork (https://github.com/pyldap)

Infrastructure:
- Add .gitignore
- Re-format README to ReStructured Text
- Setup for automatic testing using Travis CI

Modules/
(thanks to Michael Ströder)
* removed unused code schema.c
* 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/
(thanks to Michael Ströder)
* ldap.__version__, ldap.__author__ and ldap.__license__ now
imported from new sub-module ldap.pkginfo also to setup.py
* Added safety assertion when importing _ldap:
Expand All @@ -58,9 +41,35 @@ Lib/
but should not be used in new code because they might be removed
in a later release.
* removed SSSRequestControl from ldap.controls.KNOWN_RESPONSE_CONTROLS
* 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

Lib/slapdtest.py
* Automatically try some common locations for SCHEMADIR
* Ensure server is stopped when the process exits

Tests/
(thanks to Michael Ströder)
* added explicit reconnect tests for ReconnectLDAPObject
* 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)

Tests/
(thanks to pyldap contributors):
* Expand cidict membership test
* Add test suite for binds
* Add test suite for edits
* Add a smoke-check for listall() and attribute_types()

----------------------------------------------------------------
Released 2.4.45 2017-10-09
Expand Down
10 changes: 6 additions & 4 deletions Demo/Lib/ldap/async/deltree.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import print_function

import ldap,ldap.async

class DeleteLeafs(ldap.async.AsyncSearchHandler):
Expand All @@ -15,7 +17,7 @@ def __init__(self,l):

def startSearch(self,searchRoot,searchScope):
if not searchScope in [ldap.SCOPE_ONELEVEL,ldap.SCOPE_SUBTREE]:
raise ValueError, "Parameter searchScope must be either ldap.SCOPE_ONELEVEL or ldap.SCOPE_SUBTREE."
raise ValueError("Parameter searchScope must be either ldap.SCOPE_ONELEVEL or ldap.SCOPE_SUBTREE.")
self.nonLeafEntries = []
self.deletedEntries = 0
ldap.async.AsyncSearchHandler.startSearch(
Expand All @@ -28,7 +30,7 @@ def startSearch(self,searchRoot,searchScope):
)

def _processSingleResult(self,resultType,resultItem):
if self._entryResultTypes.has_key(resultType):
if resultType in self._entryResultTypes:
# Don't process search references
dn,entry = resultItem
hasSubordinates = entry.get(
Expand All @@ -45,7 +47,7 @@ def _processSingleResult(self,resultType,resultItem):
else:
try:
self._l.delete_s(dn)
except ldap.NOT_ALLOWED_ON_NONLEAF,e:
except ldap.NOT_ALLOWED_ON_NONLEAF as e:
self.nonLeafEntries.append(dn)
else:
self.deletedEntries = self.deletedEntries+1
Expand All @@ -62,7 +64,7 @@ def DelTree(l,dn,scope=ldap.SCOPE_ONELEVEL):
non_leaf_entries = leafs_deleter.nonLeafEntries[:]
while non_leaf_entries:
dn = non_leaf_entries.pop()
print deleted_entries,len(non_leaf_entries),dn
print(deleted_entries,len(non_leaf_entries),dn)
leafs_deleter.startSearch(dn,ldap.SCOPE_SUBTREE)
leafs_deleter.processResults()
deleted_entries = deleted_entries+leafs_deleter.deletedEntries
Expand Down
10 changes: 5 additions & 5 deletions Demo/Lib/ldapurl/urlsearch.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,30 @@
No output of LDAP data is produced except trace output.
"""

from __future__ import print_function
import sys,getpass,ldap,ldapurl

try:
ldapUrl = ldapurl.LDAPUrl(ldapUrl=sys.argv[1])
except IndexError:
print 'Usage: %s [LDAP URL]' % (sys.argv[0])
print('Usage: %s [LDAP URL]' % (sys.argv[0]))
sys.exit(1)

for a in [
'urlscheme','hostport','dn','attrs','scope',
'filterstr','extensions','who','cred'
]:
print a,repr(getattr(ldapUrl,a))
print(a,repr(getattr(ldapUrl,a)))

l = ldap.initialize(ldapUrl.initializeUrl(),trace_level=1)
if ldapUrl.who!=None:
if ldapUrl.cred!=None:
cred=ldapUrl.cred
else:
print 'Enter password for simple bind with',repr(ldapUrl.who)
print('Enter password for simple bind with',repr(ldapUrl.who))
cred=getpass.getpass()
l.simple_bind_s(ldapUrl.who,cred)

res = l.search_s(ldapUrl.dn,ldapUrl.scope,ldapUrl.filterstr,ldapUrl.attrs)

print len(res),'search results'
print(len(res),'search results')
21 changes: 11 additions & 10 deletions Demo/initialize.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
ldaps://localhost:1391 (LDAP over SSL)
ldapi://%2ftmp%2fopenldap2 (domain socket /tmp/openldap2)
"""
from __future__ import print_function

import sys,os,ldap

Expand All @@ -23,10 +24,10 @@
# Complete path name of the file containing all trusted CA certs
CACERTFILE='/etc/ssl/ca-bundle.pem'

print """##################################################################
print("""##################################################################
# LDAPv3 connection with StartTLS ext. op.
##################################################################
"""
""")

# Create LDAPObject instance
l = ldap.initialize('ldap://localhost:1390',trace_level=ldapmodule_trace_level,trace_file=ldapmodule_trace_file)
Expand All @@ -44,19 +45,19 @@
# Now try StartTLS extended operation
l.start_tls_s()

print '***ldap.OPT_X_TLS_VERSION',l.get_option(ldap.OPT_X_TLS_VERSION)
print '***ldap.OPT_X_TLS_CIPHER',l.get_option(ldap.OPT_X_TLS_CIPHER)
print('***ldap.OPT_X_TLS_VERSION',l.get_option(ldap.OPT_X_TLS_VERSION))
print('***ldap.OPT_X_TLS_CIPHER',l.get_option(ldap.OPT_X_TLS_CIPHER))

# Try an explicit anon bind to provoke failure
l.simple_bind_s('','')

# Close connection
l.unbind_s()

print """##################################################################
print("""##################################################################
# LDAPv3 connection over SSL
##################################################################
"""
""")

# Create LDAPObject instance
l = ldap.initialize('ldaps://localhost:1391',trace_level=ldapmodule_trace_level,trace_file=ldapmodule_trace_file)
Expand All @@ -74,16 +75,16 @@
# Try an explicit anon bind to provoke failure
l.simple_bind_s('','')

print '***ldap.OPT_X_TLS_VERSION',l.get_option(ldap.OPT_X_TLS_VERSION)
print '***ldap.OPT_X_TLS_CIPHER',l.get_option(ldap.OPT_X_TLS_CIPHER)
print('***ldap.OPT_X_TLS_VERSION',l.get_option(ldap.OPT_X_TLS_VERSION))
print('***ldap.OPT_X_TLS_CIPHER',l.get_option(ldap.OPT_X_TLS_CIPHER))

# Close connection
l.unbind_s()

print """##################################################################
print("""##################################################################
# LDAPv3 connection over Unix domain socket
##################################################################
"""
""")

# Create LDAPObject instance
l = ldap.initialize('ldapi://%2ftmp%2fopenldap-socket',trace_level=ldapmodule_trace_level,trace_file=ldapmodule_trace_file)
Expand Down
9 changes: 5 additions & 4 deletions Demo/ldapcontrols.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
from __future__ import print_function
import ldap,ldapurl,pprint

from ldap.controls import LDAPControl,BooleanControl

l = ldap.initialize('ldap://localhost:1390',trace_level=2)

print 60*'#'
print(60*'#')

pprint.pprint(l.get_option(ldap.OPT_SERVER_CONTROLS))
l.manage_dsa_it(1,1)
pprint.pprint(l.get_option(ldap.OPT_SERVER_CONTROLS))
print 60*'#'
print(60*'#')

# Search with ManageDsaIT control (which has no value)
pprint.pprint(l.search_ext_s(
Expand All @@ -19,7 +20,7 @@
['*','+'],
serverctrls = [ LDAPControl('2.16.840.1.113730.3.4.2',1,None) ],
))
print 60*'#'
print(60*'#')

# Search with Subentries control (which has boolean value)
pprint.pprint(l.search_ext_s(
Expand All @@ -30,4 +31,4 @@
serverctrls = [ BooleanControl('1.3.6.1.4.1.4203.1.10.1',1,1) ],
))

print 60*'#'
print(60*'#')
6 changes: 4 additions & 2 deletions Demo/ldapurl_search.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import print_function

import sys,pprint,ldap

from ldap.ldapobject import LDAPObject
Expand All @@ -15,7 +17,7 @@ class MyLDAPUrl(LDAPUrl):
ldap_url = MyLDAPUrl(sys.argv[1])
trace_level = int(ldap_url.trace_level or '0')

print '***trace_level',trace_level
print('***trace_level',trace_level)

ldap.trace_level = trace_level

Expand All @@ -37,6 +39,6 @@ class MyLDAPUrl(LDAPUrl):

pprint.pprint(result)

print '***DIAGNOSTIC_MESSAGE',repr(l.get_option(ldap.OPT_DIAGNOSTIC_MESSAGE))
print('***DIAGNOSTIC_MESSAGE',repr(l.get_option(ldap.OPT_DIAGNOSTIC_MESSAGE)))

l.unbind_s()
13 changes: 7 additions & 6 deletions Demo/matchedvalues.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,17 @@
# Matched values control: (mail=*@example.org)
# dn: uid=jsmith,ou=People,dc=example,dc=com
# mail: jsmith@example.org
from __future__ import print_function

import ldap
from ldap.controls import MatchedValuesControl

def print_result(search_result):
for n in range(len(search_result)):
print "dn: %s" % search_result[n][0]
print("dn: %s" % search_result[n][0])
for attr in search_result[n][1].keys():
for i in range(len(search_result[n][1][attr])):
print "%s: %s" % (attr, search_result[n][1][attr][i])
print("%s: %s" % (attr, search_result[n][1][attr][i]))
print


Expand All @@ -51,13 +52,13 @@ def print_result(search_result):
mv = MatchedValuesControl(criticality=True, controlValue=control_filter)

res = ld.search_ext_s(base, scope, filter, attrlist = ['mail'])
print "LDAP filter used: %s" % filter
print "Requesting 'mail' attribute back"
print("LDAP filter used: %s" % filter)
print("Requesting 'mail' attribute back")
print
print "No matched values control:"
print("No matched values control:")
print_result(res)

res = ld.search_ext_s(base, scope, filter, attrlist = ['mail'], serverctrls = [mv])
print "Matched values control: %s" % control_filter
print("Matched values control: %s" % control_filter)
print_result(res)

Loading

0 comments on commit 4c9c526

Please sign in to comment.