2323
2424HERE = os .path .abspath (os .path .dirname (__file__ ))
2525
26- # a template string for generating simple slapd.conf file
27- SLAPD_CONF_TEMPLATE = r"""
28- serverID %(serverid)s
29- moduleload back_%(database)s
30- %(include_directives)s
31- loglevel %(loglevel)s
32- allow bind_v2
33-
34- authz-regexp
35- "gidnumber=%(root_gid)s\\+uidnumber=%(root_uid)s,cn=peercred,cn=external,cn=auth"
36- "%(rootdn)s"
37-
38- database %(database)s
39- directory "%(directory)s"
40- suffix "%(suffix)s"
41- rootdn "%(rootdn)s"
42- rootpw "%(rootpw)s"
43-
44- TLSCACertificateFile "%(cafile)s"
45- TLSCertificateFile "%(servercert)s"
46- TLSCertificateKeyFile "%(serverkey)s"
47- # ignore missing client cert but fail with invalid client cert
48- TLSVerifyClient try
49-
50- authz-regexp
51- "C=DE, O=python-ldap, OU=slapd-test, CN=([A-Za-z]+)"
52- "ldap://ou=people,dc=local???($1)"
53-
26+ # a template string for generating simple slapd.d file
27+ SLAPD_CONF_TEMPLATE = r"""dn: cn=config
28+ objectClass: olcGlobal
29+ cn: config
30+ olcServerID: %(serverid)s
31+ olcLogLevel: %(loglevel)s
32+ olcAllows: bind_v2
33+ olcAuthzRegexp: {0}"gidnumber=%(root_gid)s\+uidnumber=%(root_uid)s,cn=peercred,cn=external,cn=auth" "%(rootdn)s"
34+ olcAuthzRegexp: {1}"C=DE, O=python-ldap, OU=slapd-test, CN=([A-Za-z]+)" "ldap://ou=people,dc=local???($1)"
35+ olcTLSCACertificateFile: %(cafile)s
36+ olcTLSCertificateFile: %(servercert)s
37+ olcTLSCertificateKeyFile: %(serverkey)s
38+ olcTLSVerifyClient: try
39+
40+ dn: cn=module,cn=config
41+ objectClass: olcModuleList
42+ cn: module
43+ olcModuleLoad: back_%(database)s
44+
45+ dn: olcDatabase=%(database)s,cn=config
46+ objectClass: olcDatabaseConfig
47+ objectClass: olcMdbConfig
48+ olcDatabase: %(database)s
49+ olcSuffix: %(suffix)s
50+ olcRootDN: %(rootdn)s
51+ olcRootPW: %(rootpw)s
52+ olcDbDirectory: %(directory)s
5453"""
5554
5655LOCALHOST = '127.0.0.1'
@@ -175,6 +174,9 @@ class SlapdObject(object):
175174 manager, the slapd server is shut down and the temporary data store is
176175 removed.
177176
177+ :param openldap_schema_files: A list of schema names or schema paths to
178+ load at startup. By default this only contains `core`.
179+
178180 .. versionchanged:: 3.1
179181
180182 Added context manager functionality
@@ -187,10 +189,10 @@ class SlapdObject(object):
187189 slapd_loglevel = 'stats stats2'
188190 local_host = LOCALHOST
189191 testrunsubdirs = (
190- 'schema ' ,
192+ 'slapd.d ' ,
191193 )
192194 openldap_schema_files = (
193- 'core.schema ' ,
195+ 'core.ldif ' ,
194196 )
195197
196198 TMPDIR = os .environ .get ('TMP' , os .getcwd ())
@@ -217,8 +219,7 @@ def __init__(self):
217219 self ._port = self ._avail_tcp_port ()
218220 self .server_id = self ._port % 4096
219221 self .testrundir = os .path .join (self .TMPDIR , 'python-ldap-test-%d' % self ._port )
220- self ._schema_prefix = os .path .join (self .testrundir , 'schema' )
221- self ._slapd_conf = os .path .join (self .testrundir , 'slapd.conf' )
222+ self ._slapd_conf = os .path .join (self .testrundir , 'slapd.d' )
222223 self ._db_directory = os .path .join (self .testrundir , "openldap-data" )
223224 self .ldap_uri = "ldap://%s:%d/" % (self .local_host , self ._port )
224225 if HAVE_LDAPI :
@@ -262,6 +263,7 @@ def _find_commands(self):
262263 self .PATH_LDAPDELETE = self ._find_command ('ldapdelete' )
263264 self .PATH_LDAPMODIFY = self ._find_command ('ldapmodify' )
264265 self .PATH_LDAPWHOAMI = self ._find_command ('ldapwhoami' )
266+ self .PATH_SLAPADD = self ._find_command ('slapadd' )
265267
266268 self .PATH_SLAPD = os .environ .get ('SLAPD' , None )
267269 if not self .PATH_SLAPD :
@@ -292,7 +294,6 @@ def setup_rundir(self):
292294 os .mkdir (self .testrundir )
293295 os .mkdir (self ._db_directory )
294296 self ._create_sub_dirs (self .testrunsubdirs )
295- self ._ln_schema_files (self .openldap_schema_files , self .SCHEMADIR )
296297
297298 def _cleanup_rundir (self ):
298299 """
@@ -337,17 +338,8 @@ def gen_config(self):
337338 for generating specific static configuration files you have to
338339 override this method
339340 """
340- include_directives = '\n ' .join (
341- 'include "{schema_prefix}/{schema_file}"' .format (
342- schema_prefix = self ._schema_prefix ,
343- schema_file = schema_file ,
344- )
345- for schema_file in self .openldap_schema_files
346- )
347341 config_dict = {
348342 'serverid' : hex (self .server_id ),
349- 'schema_prefix' :self ._schema_prefix ,
350- 'include_directives' : include_directives ,
351343 'loglevel' : self .slapd_loglevel ,
352344 'database' : self .database ,
353345 'directory' : self ._db_directory ,
@@ -371,29 +363,28 @@ def _create_sub_dirs(self, dir_names):
371363 self ._log .debug ('Create directory %s' , dir_name )
372364 os .mkdir (dir_name )
373365
374- def _ln_schema_files (self , file_names , source_dir ):
375- """
376- write symbolic links to original schema files
377- """
378- for fname in file_names :
379- ln_source = os .path .join (source_dir , fname )
380- ln_target = os .path .join (self ._schema_prefix , fname )
381- self ._log .debug ('Create symlink %s -> %s' , ln_source , ln_target )
382- os .symlink (ln_source , ln_target )
383-
384366 def _write_config (self ):
385- """Writes the slapd.conf file out, and returns the path to it."""
386- self ._log .debug ('Writing config to %s' , self ._slapd_conf )
387- with open (self ._slapd_conf , 'w' ) as config_file :
388- config_file .write (self .gen_config ())
389- self ._log .info ('Wrote config to %s' , self ._slapd_conf )
367+ """Loads the slapd.d configuration."""
368+ self ._log .debug ("importing configuration: %s" , self ._slapd_conf )
369+
370+ self .slapadd (self .gen_config (), ["-n0" ])
371+ ldif_paths = [
372+ schema
373+ if os .path .exists (schema )
374+ else os .path .join (self .SCHEMADIR , schema )
375+ for schema in self .openldap_schema_files
376+ ]
377+ for ldif_path in ldif_paths :
378+ self .slapadd (None , ["-n0" , "-l" , ldif_path ])
379+
380+ self ._log .debug ("import ok: %s" , self ._slapd_conf )
390381
391382 def _test_config (self ):
392383 self ._log .debug ('testing config %s' , self ._slapd_conf )
393384 popen_list = [
394385 self .PATH_SLAPD ,
395386 "-Ttest" ,
396- "-f " , self ._slapd_conf ,
387+ "-F " , self ._slapd_conf ,
397388 "-u" ,
398389 "-v" ,
399390 "-d" , "config"
@@ -417,8 +408,7 @@ def _start_slapd(self):
417408 urls .append (self .ldapi_uri )
418409 slapd_args = [
419410 self .PATH_SLAPD ,
420- '-f' , self ._slapd_conf ,
421- '-F' , self .testrundir ,
411+ '-F' , self ._slapd_conf ,
422412 '-h' , ' ' .join (urls ),
423413 ]
424414 if self ._log .isEnabledFor (logging .DEBUG ):
@@ -523,10 +513,14 @@ def _cli_popen(self, ldapcommand, extra_args=None, ldap_uri=None,
523513 stdin_data = None ): # pragma: no cover
524514 if ldap_uri is None :
525515 ldap_uri = self .default_ldap_uri
526- args = [
527- ldapcommand ,
528- '-H' , ldap_uri ,
529- ] + self ._cli_auth_args () + (extra_args or [])
516+
517+ if ldapcommand .split ("/" )[- 1 ].startswith ("ldap" ):
518+ args = [ldapcommand , '-H' , ldap_uri ] + self ._cli_auth_args ()
519+ else :
520+ args = [ldapcommand , '-F' , self ._slapd_conf ]
521+
522+ args += (extra_args or [])
523+
530524 self ._log .debug ('Run command: %r' , ' ' .join (args ))
531525 proc = subprocess .Popen (
532526 args , stdin = subprocess .PIPE , stdout = subprocess .PIPE ,
@@ -577,6 +571,16 @@ def ldapdelete(self, dn, recursive=False, extra_args=None):
577571 extra_args .append (dn )
578572 self ._cli_popen (self .PATH_LDAPDELETE , extra_args = extra_args )
579573
574+ def slapadd (self , ldif , extra_args = None ):
575+ """
576+ Runs slapadd on this slapd instance, passing it the ldif content
577+ """
578+ self ._cli_popen (
579+ self .PATH_SLAPADD ,
580+ stdin_data = ldif .encode ("utf-8" ) if ldif else None ,
581+ extra_args = extra_args ,
582+ )
583+
580584 def __enter__ (self ):
581585 self .start ()
582586 return self
0 commit comments