mirror of
https://git.openldap.org/openldap/openldap.git
synced 2026-02-18 18:18:06 -05:00
Merge branch 'python-ldap' into 'master'
Port python test suite to python-ldap See merge request openldap/openldap!732
This commit is contained in:
commit
8b0bdec6da
4 changed files with 69 additions and 44 deletions
|
|
@ -20,7 +20,7 @@
|
||||||
OpenLDAP fixtures for backends
|
OpenLDAP fixtures for backends
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import ldap0
|
import ldap
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import pathlib
|
import pathlib
|
||||||
|
|
@ -28,7 +28,7 @@ import pytest
|
||||||
import secrets
|
import secrets
|
||||||
import tempfile
|
import tempfile
|
||||||
|
|
||||||
from ldap0.controls.readentry import PostReadControl
|
from ldap.controls.readentry import PostReadControl
|
||||||
|
|
||||||
from .slapd import server
|
from .slapd import server
|
||||||
|
|
||||||
|
|
@ -36,6 +36,7 @@ from .slapd import server
|
||||||
SOURCEROOT = pathlib.Path(os.environ.get('TOP_SRCDIR', "..")).absolute()
|
SOURCEROOT = pathlib.Path(os.environ.get('TOP_SRCDIR', "..")).absolute()
|
||||||
BUILDROOT = pathlib.Path(os.environ.get('TOP_BUILDDIR', SOURCEROOT)).absolute()
|
BUILDROOT = pathlib.Path(os.environ.get('TOP_BUILDDIR', SOURCEROOT)).absolute()
|
||||||
|
|
||||||
|
NOTSET = object()
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
@ -43,10 +44,17 @@ logger = logging.getLogger(__name__)
|
||||||
class Database:
|
class Database:
|
||||||
have_directory = True
|
have_directory = True
|
||||||
|
|
||||||
def __init__(self, server, suffix, backend):
|
def __init__(self, server, suffix, backend, *,
|
||||||
|
rootdn=NOTSET, module=NOTSET):
|
||||||
|
if rootdn is NOTSET:
|
||||||
|
rootdn = suffix
|
||||||
|
if module is NOTSET:
|
||||||
|
module = (BUILDROOT/"servers"/"slapd"/
|
||||||
|
f"back-{backend}"/f"back_{backend}")
|
||||||
|
|
||||||
self.server = server
|
self.server = server
|
||||||
self.suffix = suffix
|
self.suffix = suffix
|
||||||
self.rootdn = suffix
|
self.rootdn = rootdn
|
||||||
self.secret = secrets.token_urlsafe()
|
self.secret = secrets.token_urlsafe()
|
||||||
self.overlays = []
|
self.overlays = []
|
||||||
|
|
||||||
|
|
@ -54,18 +62,21 @@ class Database:
|
||||||
raise RuntimeError(f"Suffix {suffix} already configured in server")
|
raise RuntimeError(f"Suffix {suffix} already configured in server")
|
||||||
|
|
||||||
if self.have_directory:
|
if self.have_directory:
|
||||||
self.directory = tempfile.TemporaryDirectory(dir=server.home)
|
self.directory = tempfile.TemporaryDirectory(dir=server.home, delete=False)
|
||||||
|
|
||||||
|
if module:
|
||||||
|
server.load_module(module)
|
||||||
|
|
||||||
conn = server.connect()
|
conn = server.connect()
|
||||||
conn.simple_bind_s("cn=config", server.secret)
|
conn.simple_bind_s("cn=config", server.secret)
|
||||||
|
|
||||||
# We're just after the generated DN, no other attributes at the moment
|
# We're just after the generated DN, no other attributes at the moment
|
||||||
control = PostReadControl(True, [])
|
control = PostReadControl(True, ["1.1"])
|
||||||
|
|
||||||
result = conn.add_s(
|
_, _, _, ctrls = conn.add_ext_s(
|
||||||
f"olcDatabase={backend},cn=config", self._entry(),
|
f"olcDatabase={backend},cn=config", list(self._entry().items()),
|
||||||
req_ctrls=[control])
|
serverctrls=[control])
|
||||||
dn = result.ctrls[0].res.dn_s
|
dn = ctrls[0].dn
|
||||||
|
|
||||||
self.dn = dn
|
self.dn = dn
|
||||||
server.suffixes[suffix] = self
|
server.suffixes[suffix] = self
|
||||||
|
|
@ -74,9 +85,11 @@ class Database:
|
||||||
entry = {
|
entry = {
|
||||||
"objectclass": [self.objectclass.encode()],
|
"objectclass": [self.objectclass.encode()],
|
||||||
"olcSuffix": [self.suffix.encode()],
|
"olcSuffix": [self.suffix.encode()],
|
||||||
"olcRootDN": [self.suffix.encode()],
|
|
||||||
"olcRootPW": [self.secret.encode()],
|
|
||||||
}
|
}
|
||||||
|
if self.rootdn is not None:
|
||||||
|
entry["olcRootDN"] = [self.rootdn.encode()]
|
||||||
|
if self.rootdn.endswith(self.suffix):
|
||||||
|
entry["olcRootPW"] = [self.secret.encode()]
|
||||||
if self.have_directory:
|
if self.have_directory:
|
||||||
entry["olcDbDirectory"] = [self.directory.name.encode()]
|
entry["olcDbDirectory"] = [self.directory.name.encode()]
|
||||||
return entry
|
return entry
|
||||||
|
|
@ -92,10 +105,9 @@ class MDB(Database):
|
||||||
super().__init__(server, suffix, "mdb")
|
super().__init__(server, suffix, "mdb")
|
||||||
|
|
||||||
def _entry(self):
|
def _entry(self):
|
||||||
entry = {
|
return super()._entry() | {
|
||||||
"olcDbMaxSize": [str(self._size).encode()],
|
"olcDbMaxSize": [str(self._size).encode()],
|
||||||
}
|
}
|
||||||
return {**super()._entry(), **entry}
|
|
||||||
|
|
||||||
|
|
||||||
class LDAP(Database):
|
class LDAP(Database):
|
||||||
|
|
@ -107,15 +119,24 @@ class LDAP(Database):
|
||||||
super().__init__(server, suffix, "ldap")
|
super().__init__(server, suffix, "ldap")
|
||||||
|
|
||||||
def _entry(self):
|
def _entry(self):
|
||||||
entry = {
|
return super()._entry() | {
|
||||||
"olcDbURI": [" ".join(self.uris).encode()],
|
"olcDbURI": [" ".join(self.uris).encode()],
|
||||||
}
|
}
|
||||||
return {**super()._entry(), **entry}
|
|
||||||
|
|
||||||
|
class Monitor(Database):
|
||||||
|
have_directory = False
|
||||||
|
objectclass = "olcMonitorConfig"
|
||||||
|
|
||||||
|
def __init__(self, server):
|
||||||
|
super().__init__(server, "cn=monitor", "monitor",
|
||||||
|
rootdn="cn=config", module=None)
|
||||||
|
|
||||||
|
|
||||||
backend_types = {
|
backend_types = {
|
||||||
"mdb": MDB,
|
"mdb": MDB,
|
||||||
"ldap": LDAP,
|
"ldap": LDAP,
|
||||||
|
"monitor": Monitor,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ import logging
|
||||||
import os
|
import os
|
||||||
import pathlib
|
import pathlib
|
||||||
|
|
||||||
from ldap0.controls.readentry import PostReadControl
|
from ldap.controls.readentry import PostReadControl
|
||||||
|
|
||||||
|
|
||||||
SOURCEROOT = pathlib.Path(os.environ.get('TOP_SRCDIR', "..")).absolute()
|
SOURCEROOT = pathlib.Path(os.environ.get('TOP_SRCDIR', "..")).absolute()
|
||||||
|
|
@ -51,12 +51,13 @@ class Overlay:
|
||||||
server.load_module(overlay)
|
server.load_module(overlay)
|
||||||
|
|
||||||
# We're just after the generated DN, no other attributes at the moment
|
# We're just after the generated DN, no other attributes at the moment
|
||||||
control = PostReadControl(True, [])
|
control = PostReadControl(True, ["1.1"])
|
||||||
|
|
||||||
result = conn.add_s(
|
_, _, _, ctrls = conn.add_ext_s(
|
||||||
f"olcOverlay={overlay_name},{database.dn}", self._entry(),
|
f"olcOverlay={overlay_name},{database.dn}",
|
||||||
req_ctrls=[control])
|
list(self._entry().items()),
|
||||||
self.dn = result.ctrls[0].res.dn_s
|
serverctrls=[control])
|
||||||
|
self.dn = ctrls[0].dn
|
||||||
|
|
||||||
if order == -1:
|
if order == -1:
|
||||||
database.overlays.append(self)
|
database.overlays.append(self)
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@
|
||||||
OpenLDAP server fixtures
|
OpenLDAP server fixtures
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import ldap0
|
import ldap
|
||||||
import ldapurl
|
import ldapurl
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
|
@ -34,7 +34,7 @@ import subprocess
|
||||||
import tempfile
|
import tempfile
|
||||||
import textwrap
|
import textwrap
|
||||||
|
|
||||||
from ldap0.ldapobject import LDAPObject
|
from ldap.ldapobject import LDAPObject
|
||||||
|
|
||||||
|
|
||||||
SOURCEROOT = pathlib.Path(os.environ.get('TOP_SRCDIR', "..")).absolute()
|
SOURCEROOT = pathlib.Path(os.environ.get('TOP_SRCDIR', "..")).absolute()
|
||||||
|
|
@ -208,12 +208,13 @@ class Server:
|
||||||
conn.simple_bind_s('cn=config', self.secret)
|
conn.simple_bind_s('cn=config', self.secret)
|
||||||
|
|
||||||
moduleload_object = None
|
moduleload_object = None
|
||||||
for entry in conn.search_s('cn=config', ldap0.SCOPE_SUBTREE,
|
for dn, attrs in conn.search_s('cn=config', ldap.SCOPE_SUBTREE,
|
||||||
'objectclass=olcModuleList',
|
'objectclass=olcModuleList',
|
||||||
['olcModuleLoad']):
|
['olcModuleLoad']):
|
||||||
if not moduleload_object:
|
if not moduleload_object:
|
||||||
moduleload_object = entry.dn_s
|
moduleload_object = dn
|
||||||
for value in entry.entry_s.get('olcModuleLoad', []):
|
for value in attrs.get('olcModuleLoad', []):
|
||||||
|
value = value.decode()
|
||||||
if value[0] == '{':
|
if value[0] == '{':
|
||||||
value = value[value.find('}')+1:]
|
value = value[value.find('}')+1:]
|
||||||
if pathlib.Path(value).stem == module_name:
|
if pathlib.Path(value).stem == module_name:
|
||||||
|
|
@ -224,11 +225,11 @@ class Server:
|
||||||
if moduleload_object:
|
if moduleload_object:
|
||||||
conn.modify_s(
|
conn.modify_s(
|
||||||
moduleload_object,
|
moduleload_object,
|
||||||
[(ldap0.MOD_ADD, b'olcModuleLoad', [str(module).encode()])])
|
[(ldap.MOD_ADD, 'olcModuleLoad', [str(module).encode()])])
|
||||||
else:
|
else:
|
||||||
conn.add_s('cn=module,cn=config',
|
entry = {'objectClass': [b'olcModuleList'],
|
||||||
{'objectClass': [b'olcModuleList'],
|
'olcModuleLoad': [str(module).encode()]}
|
||||||
'olcModuleLoad': [str(module).encode()]})
|
conn.add_s('cn=module,cn=config', list(entry.items()))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def uri(self):
|
def uri(self):
|
||||||
|
|
@ -251,7 +252,7 @@ class ServerManager:
|
||||||
return self.address[1]
|
return self.address[1]
|
||||||
|
|
||||||
def new_server(self):
|
def new_server(self):
|
||||||
path = tempfile.TemporaryDirectory(dir=self.tmpdir)
|
path = tempfile.TemporaryDirectory(dir=self.tmpdir, delete=False)
|
||||||
return Server(path, self)
|
return Server(path, self)
|
||||||
|
|
||||||
def wait(self, token):
|
def wait(self, token):
|
||||||
|
|
@ -292,4 +293,4 @@ def server(server_factory):
|
||||||
|
|
||||||
def test_rootdse(server):
|
def test_rootdse(server):
|
||||||
conn = server.connect()
|
conn = server.connect()
|
||||||
conn.search_s("", scope=ldap0.SCOPE_BASE)
|
conn.search_s("", scope=ldap.SCOPE_BASE)
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@
|
||||||
OpenLDAP fixtures for overlays
|
OpenLDAP fixtures for overlays
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import ldap0
|
import ldap
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import pathlib
|
import pathlib
|
||||||
|
|
@ -86,7 +86,7 @@ def mmr(request, server_factory):
|
||||||
conn.simple_bind_s("cn=config", server.secret)
|
conn.simple_bind_s("cn=config", server.secret)
|
||||||
|
|
||||||
conn.modify_s("cn=config", [
|
conn.modify_s("cn=config", [
|
||||||
(ldap0.MOD_REPLACE, b"olcServerId", [str(serverid).encode()])])
|
(ldap.MOD_REPLACE, "olcServerId", [str(serverid).encode()])])
|
||||||
|
|
||||||
server.serverid = serverid
|
server.serverid = serverid
|
||||||
servers[serverid] = server
|
servers[serverid] = server
|
||||||
|
|
@ -110,8 +110,8 @@ def mmr(request, server_factory):
|
||||||
f'binddn="{db.suffix}" credentials="{db.secret}"').encode())
|
f'binddn="{db.suffix}" credentials="{db.secret}"').encode())
|
||||||
|
|
||||||
connections[serverid].modify_s(db.dn, [
|
connections[serverid].modify_s(db.dn, [
|
||||||
(ldap0.MOD_REPLACE, b"olcSyncrepl", syncrepl),
|
(ldap.MOD_REPLACE, "olcSyncrepl", syncrepl),
|
||||||
(ldap0.MOD_REPLACE, b"olcMultiprovider", [b"TRUE"])])
|
(ldap.MOD_REPLACE, "olcMultiprovider", [b"TRUE"])])
|
||||||
|
|
||||||
yield servers
|
yield servers
|
||||||
|
|
||||||
|
|
@ -142,27 +142,29 @@ def test_mmr(mmr):
|
||||||
conn.simple_bind_s(db.rootdn, db.secret)
|
conn.simple_bind_s(db.rootdn, db.secret)
|
||||||
|
|
||||||
if not entries_added:
|
if not entries_added:
|
||||||
conn.add_s(suffix, {
|
entry = {
|
||||||
"objectClass": [b"organization",
|
"objectClass": [b"organization",
|
||||||
b"domainRelatedObject",
|
b"domainRelatedObject",
|
||||||
b"dcobject"],
|
b"dcobject"],
|
||||||
"o": [b"Example, Inc."],
|
"o": [b"Example, Inc."],
|
||||||
"associatedDomain": [b"example.com"]})
|
"associatedDomain": [b"example.com"]}
|
||||||
|
conn.add_s(suffix, list(entry.items()))
|
||||||
entries_added.add(suffix)
|
entries_added.add(suffix)
|
||||||
# Make sure all hosts have the suffix entry
|
# Make sure all hosts have the suffix entry
|
||||||
wait_for_resync(suffix, mmr.values())
|
wait_for_resync(suffix, mmr.values())
|
||||||
|
|
||||||
dn = f"cn=entry{serverid},{suffix}"
|
dn = f"cn=entry{serverid},{suffix}"
|
||||||
conn.add_s(dn, {"objectClass": [b"device"],
|
entry = {"objectClass": [b"device"],
|
||||||
"description": [(f"Entry created on serverid "
|
"description": [(f"Entry created on serverid "
|
||||||
f"{serverid}").encode()]})
|
f"{serverid}").encode()]}
|
||||||
|
conn.add_s(dn, list(entry.items()))
|
||||||
entries_added.add(dn)
|
entries_added.add(dn)
|
||||||
connections.append(conn)
|
connections.append(conn)
|
||||||
|
|
||||||
wait_for_resync(suffix, mmr.values())
|
wait_for_resync(suffix, mmr.values())
|
||||||
|
|
||||||
for conn in connections:
|
for conn in connections:
|
||||||
result = conn.search_s(suffix, ldap0.SCOPE_SUBTREE, attrlist=['1.1'])
|
result = conn.search_s(suffix, ldap.SCOPE_SUBTREE, attrlist=['1.1'])
|
||||||
dns = {entry.dn_s for entry in result}
|
dns = {dn for dn, entry in result}
|
||||||
assert dns == entries_added, \
|
assert dns == entries_added, \
|
||||||
f"Server {serverid} contents do not match expectations"
|
f"Server {serverid} contents do not match expectations"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue