@@ -179,6 +179,10 @@ class SlapdObject:
179179 .. versionchanged:: 3.1
180180
181181 Added context manager functionality
182+
183+ .. versionchanged:: UNRELEASED
184+
185+ Added ldaps_uri attribute
182186 """
183187 slapd_conf_template = SLAPD_CONF_TEMPLATE
184188 database = 'mdb'
@@ -212,12 +216,13 @@ class SlapdObject:
212216
213217 def __init__ (self ):
214218 self ._proc = None
215- self ._port = self ._avail_tcp_port ( )
219+ self ._port , self . _tls_port = self ._avail_tcp_ports ( 2 )
216220 self .server_id = self ._port % 4096
217221 self .testrundir = os .path .join (self .TMPDIR , 'python-ldap-test-%d' % self ._port )
218222 self ._slapd_conf = os .path .join (self .testrundir , 'slapd.d' )
219223 self ._db_directory = os .path .join (self .testrundir , "openldap-data" )
220224 self .ldap_uri = "ldap://%s:%d/" % (self .local_host , self ._port )
225+ self .ldaps_uri = "ldaps://%s:%d/" % (self .local_host , self ._tls_port )
221226 if HAVE_LDAPI :
222227 ldapi_path = os .path .join (self .testrundir , 'ldapi' )
223228 self .ldapi_uri = "ldapi://%s" % quote_plus (ldapi_path )
@@ -314,18 +319,26 @@ def _cleanup_rundir(self):
314319 os .rmdir (self .testrundir )
315320 self ._log .info ('cleaned-up %s' , self .testrundir )
316321
322+ def _avail_tcp_ports (self , n ):
323+ """Return a list of currently unused TCP port numbers.
324+ """
325+ ports = []
326+ socks = [socket .socket (socket .AF_INET , socket .SOCK_STREAM ) for _i in range (n )]
327+ try :
328+ for sock in socks :
329+ sock .setsockopt (socket .SOL_SOCKET , socket .SO_REUSEADDR , 1 )
330+ sock .bind ((self .local_host , 0 ))
331+ ports .append (sock .getsockname ()[1 ])
332+ finally :
333+ [sock .close () for sock in socks ]
334+ self ._log .info ('Found available port(s) %s' , socks )
335+ return ports
336+
317337 def _avail_tcp_port (self ):
318338 """
319339 find an available port for TCP connection
320340 """
321- sock = socket .socket ()
322- try :
323- sock .bind ((self .local_host , 0 ))
324- port = sock .getsockname ()[1 ]
325- finally :
326- sock .close ()
327- self ._log .info ('Found available port %d' , port )
328- return port
341+ return self ._avail_tcp_ports (1 )
329342
330343 def gen_config (self ):
331344 """
@@ -399,7 +412,7 @@ def _start_slapd(self):
399412 """
400413 Spawns/forks the slapd process
401414 """
402- urls = [self .ldap_uri ]
415+ urls = [self .ldap_uri , self . ldaps_uri ]
403416 if self .ldapi_uri :
404417 urls .append (self .ldapi_uri )
405418 slapd_args = [
@@ -425,13 +438,18 @@ def _start_slapd(self):
425438 self ._log .debug (
426439 "slapd connection check to %s" , self .default_ldap_uri
427440 )
428- self .ldapwhoami ()
441+ # try all bound sockets to make sure the daemon is ready to go.
442+ self .ldapwhoami (ldap_uri = self .ldap_uri )
443+ self .ldapwhoami (ldap_uri = self .ldaps_uri )
444+ if self .ldapi_uri :
445+ self .ldapwhoami (ldap_uri = self .ldapi_uri )
429446 except RuntimeError :
430447 if time .monotonic () >= deadline :
431448 break
432449 time .sleep (0.2 )
433450 else :
434451 return
452+ self ._proc .kill ()
435453 raise RuntimeError ("slapd did not start properly" )
436454
437455 def start (self ):
@@ -448,8 +466,8 @@ def start(self):
448466 self ._test_config ()
449467 self ._start_slapd ()
450468 self ._log .debug (
451- 'slapd with pid=%d listening on %s and %s' ,
452- self ._proc .pid , self .ldap_uri , self .ldapi_uri
469+ 'slapd with pid=%d listening on %s, %s and %s' ,
470+ self ._proc .pid , self .ldap_uri , self .ldaps_uri , self . ldapi_uri
453471 )
454472
455473 def stop (self ):
@@ -483,8 +501,8 @@ def _stopped(self):
483501 self ._log .info ('slapd[%d] terminated' , self ._proc .pid )
484502 self ._proc = None
485503
486- def _cli_auth_args (self ):
487- if self . cli_sasl_external :
504+ def _cli_remote_args (self , ldap_uri ):
505+ if ldap_uri . startswith ( 'ldapi://' ) :
488506 authc_args = [
489507 '-Y' , 'EXTERNAL' ,
490508 ]
@@ -496,16 +514,36 @@ def _cli_auth_args(self):
496514 '-D' , self .root_dn ,
497515 '-w' , self .root_pw ,
498516 ]
499- return authc_args
517+ return [ '-H' , ldap_uri ] + authc_args
500518
501519 # no cover to avoid spurious coverage changes
502520 def _cli_popen (self , ldapcommand , extra_args = None , ldap_uri = None ,
503521 stdin_data = None ): # pragma: no cover
504522 if ldap_uri is None :
505523 ldap_uri = self .default_ldap_uri
506524
525+ environ = os .environ .copy ()
526+
507527 if ldapcommand .split ("/" )[- 1 ].startswith ("ldap" ):
508- args = [ldapcommand , '-H' , ldap_uri ] + self ._cli_auth_args ()
528+ args = [ldapcommand ] + self ._cli_remote_args (ldap_uri )
529+
530+ # setting $LDAPNOINIT ignores all other environment and config files
531+ environ .pop ('LDAPNOINIT' , None )
532+ # we really only want to set the CA cert...
533+ environ ['LDAPTLS_CACERT' ] = self .cafile
534+ environ ['LDAPTLS_REQCERT' ] = 'demand'
535+ environ ['LDAPTLS_REQSAN' ] = 'demand'
536+ environ ['LDAPTLS_CRLCHECK' ] = 'none'
537+ environ ['LDAPTLS_CRLFILE' ] = ''
538+ # ... but need to provide more to override any system/user defaults.
539+ environ ['LDAPVERSION' ] = '3'
540+ environ ['LDAPTIMEOUT' ] = '5'
541+ environ ['LDAPTIMELIMIT' ] = '15'
542+ environ ['LDAPSIZELIMIT' ] = '12'
543+ environ ['LDAPNETWORK_TIMEOUT' ] = '5'
544+ environ ['LDAPTLS_CERT' ] = ''
545+ environ ['LDAPTLS_KEY' ] = ''
546+
509547 else :
510548 args = [ldapcommand , '-F' , self ._slapd_conf ]
511549
@@ -514,7 +552,8 @@ def _cli_popen(self, ldapcommand, extra_args=None, ldap_uri=None,
514552 self ._log .debug ('Run command: %r' , ' ' .join (args ))
515553 proc = subprocess .Popen (
516554 args , stdin = subprocess .PIPE , stdout = subprocess .PIPE ,
517- stderr = subprocess .PIPE
555+ stderr = subprocess .PIPE ,
556+ env = environ ,
518557 )
519558 self ._log .debug ('stdin_data=%r' , stdin_data )
520559 stdout_data , stderr_data = proc .communicate (stdin_data )
@@ -530,11 +569,11 @@ def _cli_popen(self, ldapcommand, extra_args=None, ldap_uri=None,
530569 )
531570 return stdout_data , stderr_data
532571
533- def ldapwhoami (self , extra_args = None ):
572+ def ldapwhoami (self , extra_args = None , ** kws ):
534573 """
535574 Runs ldapwhoami on this slapd instance
536575 """
537- self ._cli_popen (self .PATH_LDAPWHOAMI , extra_args = extra_args )
576+ self ._cli_popen (self .PATH_LDAPWHOAMI , extra_args = extra_args , ** kws )
538577
539578 def ldapadd (self , ldif , extra_args = None ):
540579 """
0 commit comments