
    ?DelL                        d Z ddlZddlZddlZddlZddlZddlZddlZddlm	Z	 ddl
Z
ddlmZ ddlmZ dej        d<   ddlZej                            ej                            e                    ZdZd	Z eej                            d
d                              d                    Zdev rdZn eed          Zd ZddZd Z d Z!d Z"d Z#d Z$ej%        ddfdZ& G d d          Z' G d de
j(                  Z)dS )zz
slapdtest - module for spawning test instances of OpenLDAP's slapd server

See https://www.python-ldap.org/ for details.
    N)SysLogHandler)which)
quote_plus1
LDAPNOINITa  dn: cn=config
objectClass: olcGlobal
cn: config
olcServerID: %(serverid)s
olcLogLevel: %(loglevel)s
olcAllows: bind_v2
olcAuthzRegexp: {0}"gidnumber=%(root_gid)s\+uidnumber=%(root_uid)s,cn=peercred,cn=external,cn=auth" "%(rootdn)s"
olcAuthzRegexp: {1}"C=DE, O=python-ldap, OU=slapd-test, CN=([A-Za-z]+)" "ldap://ou=people,dc=local???($1)"
olcTLSCACertificateFile: %(cafile)s
olcTLSCertificateFile: %(servercert)s
olcTLSCertificateKeyFile: %(serverkey)s
olcTLSVerifyClient: try

dn: cn=module,cn=config
objectClass: olcModuleList
cn: module
olcModuleLoad: back_%(database)s

dn: olcDatabase=%(database)s,cn=config
objectClass: olcDatabaseConfig
objectClass: olcMdbConfig
olcDatabase: %(database)s
olcSuffix: %(suffix)s
olcRootDN: %(rootdn)s
olcRootPW: %(rootpw)s
olcDbDirectory: %(directory)s
z	127.0.0.1CI_DISABLED :LDAPIFAF_UNIXc                     | S )zIdentity decorator

     )	test_items    /./slapdtest/_slapdtest.pyidentityr   ?   s
         c                     t           j                            dd          st          j        |           S |t
          v rt          j        |           S t          S )z@Skip test unless test case is executed on CI like Travis CI
    CIF)osenvirongetunittestskipr   r   )reasonfeatures     r   skip_unless_cir   F   sN     :>>$&& }V$$$	K		}V$$$ r   c                  J    t           j        st          dd          S t          S )zNDecorator for TLS tests

    Tests are not skipped on CI (e.g. Travis CI)
    ztest needs ldap.TLS_AVAILTLSr   )ldap	TLS_AVAILr   r   r   r   r   requires_tlsr"   R   s'    
 > 95IIIIr   c                  J    t           j        st          dd          S t          S )Nztest needs ldap.SASL_AVAILSASLr   )r    
SASL_AVAILr   r   r   r   r   requires_saslr&   ]   s/    ? (&: : : 	: r   c                  @    t           st          dd          S t          S )Nz"test needs ldapi support (AF_UNIX)r   r   )
HAVE_LDAPIr   r   r   r   r   requires_ldapir)   e   s1     0'C C C 	C r   c                  J    t           j        st          dd          S t          S )Nztest needs ldap.INIT_FDINIT_FDr   )r    INIT_FD_AVAILr   r   r   r   r   requires_init_fdr-   l   s0     %y: : : 	: r   c                     |                      t          j                  }t          j        dk    rdD ]}||vr|                    |           t          j                            |          S )z:Add /sbin and related directories to a command search pathwin32)z/usr/local/sbinz/sbinz	/usr/sbin)splitr   pathsepsysplatformappendjoin)pathdirectoriessbins      r   	_add_sbinr9   t   se    **RZ((K
|w; 	) 	)D;&&""4(((:??;'''r   z%(levelname)s %(message)sz%%(asctime)s %(levelname)s %(message)sc                    dt           j        v r3t           j        d         }	 t          |          }n# t          $ r Y nw xY wt	          j        |           }|rt           j                            d          rt	          j        d	                    | |f                    }t          j
                            dt          j                  }|                    |           |                    |           |rRt	          j        |          }t	          j                    }|                    |           |                    |           |                    |           |S )z]
    Returns a combined SysLogHandler/StreamHandler logging instance
    with formatters
    LOGLEVELz/dev/log )fmt)addressfacility)r   r   int
ValueErrorlogging	getLoggerr6   exists	Formatterr5   handlersr   
LOG_DAEMONsetFormatter
addHandlerStreamHandlersetLevel)	log_name	log_levelsys_log_formatconsole_log_format
new_loggermy_syslog_formattermy_syslog_handlermy_stream_formattermy_stream_handlers	            r   combined_loggerrU   }   sm    RZJz*		III 	 	 	D	 "8,,J 1"'..44 1%/(N3446 6 6#,::"- ; 
 
 	&&':;;;/000 1%/4FGGG#133&&':;;;/000	"""s   2 
??c                      e Zd ZdZeZdZdZdZdZ	dZ
eZdZdZej                            d	 ej                              Zd
ej        v rej        d
         Zn<ej                            d          rdZnej                            d          rdZndZej                            dej                            dej                            Zej                            d ee                    Z ed          Zd Zed             Zed             Z ed             Z!d Z"d/dZ#d Z$d Z%d Z&d Z'd Z(d Z)d Z*d  Z+d! Z,d" Z-d# Z.d$ Z/d% Z0d& Z1	 	 d0d'Z2d1d(Z3d1d)Z4d1d*Z5d2d+Z6d1d,Z7d- Z8d. Z9dS )3SlapdObjecta  
    Controller class for a slapd instance, OpenLDAP's server.

    This class creates a temporary data store for slapd, runs it
    listening on a private Unix domain socket and TCP port,
    and initializes it with a top-level entry and the root user.

    When a reference to an instance of this class is lost, the slapd
    server is shut down.

    An instance can be used as a context manager. When exiting the context
    manager, the slapd server is shut down and the temporary data store is
    removed.

    :param openldap_schema_files: A list of schema names or schema paths to
        load at startup. By default this only contains `core`.

    .. versionchanged:: 3.1

        Added context manager functionality
    mdbz#dc=slapd-test,dc=python-ldap,dc=orgManagerpasswordzstats stats2)slapd.d)z	core.ldifTMPSCHEMAz/etc/openldap/schemaz/etc/ldap/schemaNBINPATHSBINzpython-ldap-testc                    d | _         |                                 | _        | j        dz  | _        t          j                            | j        d| j        z            | _        t          j                            | j        d          | _	        t          j                            | j        d          | _
        d| j        | j        fz  | _        t          rZt          j                            | j        d          }dt          |          z  | _        | j        | _        t"          j        | _        nd | _        | j        | _        d| _        |                                  | j        t-          d	          t          j                            t.          d
          | _        t          j                            t.          d          | _        t          j                            t.          d          | _        t          j                            t.          d          | _        t          j                            t.          d          | _        d S )Ni   zpython-ldap-test-%dr[   zopenldap-datazldap://%s:%d/ldapiz
ldapi://%sFz,SCHEMADIR is None, ldap schemas are missing.zcerts/ca.pemzcerts/server.pemzcerts/server.keyzcerts/client.pemzcerts/client.key)_proc_avail_tcp_port_port	server_idr   r6   r5   TMPDIR
testrundir_slapd_conf_db_directory
local_hostldap_urir(   r   	ldapi_uridefault_ldap_urir    r%   cli_sasl_external_find_commands	SCHEMADIRrA   HEREcafile
servercert	serverkey
clientcert	clientkey)self
ldapi_paths     r   __init__zSlapdObject.__init__   s   
))++
d*',,t{4IDJ4VWW7<<CCW\\$/?KK'4?DJ*GG 
	+dow??J)Jz,B,BBDN$(ND!%)_D""!DN$(MD!%*D">!KLLL gll488',,t-?@@d,>??',,t-?@@d,>??r   c                 .    d                     |           S )Nzcn={self.root_cn},{self.suffix}rx   )formatr|   s    r   root_dnzSlapdObject.root_dn   s    077T7BBBr   c                     | j         S N)rk   r|   s    r   hostnamezSlapdObject.hostname   s
    r   c                     | j         S r   )re   r|   s    r   portzSlapdObject.port   s
    zr   c                    |                      d          | _        |                      d          | _        |                      d          | _        |                      d          | _        |                      d          | _        t          j                            dd           | _	        | j	        s|                      dd	          | _	        d S d S )
Nldapadd
ldapdelete
ldapmodify
ldapwhoamislapaddSLAPDslapdT)in_sbin)
_find_commandPATH_LDAPADDPATH_LDAPDELETEPATH_LDAPMODIFYPATH_LDAPWHOAMIPATH_SLAPADDr   r   r   
PATH_SLAPDr|   s    r   rp   zSlapdObject._find_commands  s     ..y99#11,??#11,??#11,?? ..y99*..$77 	H"00$0GGDOOO	H 	Hr   Fc                     |r
| j         }d}n	| j        }d}t          ||          }|#t          d                    ||                    |S )Nr`   r^   )r6   z\Command '{}' not found. Set the {} environment variable to override slapdtest's search path.)	SBIN_PATHBIN_PATHr   rA   r}   )rx   cmdr   r6   var_namecommands         r   r   zSlapdObject._find_command  sh     	>DHH=DH$'''?44:F34I4I   r   c                     t          j        | j                   t          j        | j                   |                     | j                   dS )z
        creates rundir structure

        for setting up a custom directory structure you have to override
        this method
        N)r   mkdirrh   rj   _create_sub_dirstestrunsubdirsr|   s    r   setup_rundirzSlapdObject.setup_rundir  sF     	!!!
#$$$d122222r   c           	         ddl }ddl}|j                            | j                  sdS | j                            d| j                    |j        | j        d          D ]\  }}}|D ]_}| j                            d|j                            ||                      |j	        |j                            ||                     `|D ]_}| j                            d|j                            ||                      |j
        |j                            ||                     ` |j
        | j                   | j                            d| j                   dS )	zH
        Recursively delete whole directory specified by `path'
        r   Nzclean-up %sF)topdownz	remove %szrmdir %szcleaned-up %s)r   os.pathr6   rD   rh   _logdebugwalkr5   removermdirinfo)rx   r   dirpathdirnames	filenamesfilenamedirnames          r   _cleanup_rundirzSlapdObject._cleanup_rundir&  sq    	w~~do.. 	F	t777,3BG- - - 		9 		9(GXy & ; ;	RW\\'8-L-LMMM	"',,w99::::# 9 9	
BGLL',J,JKKKgw7788889 	!!!	88888r   c                 ,   t          j                     }	 |                    | j        df           |                                d         }|                                 n# |                                 w xY w| j                            d|           |S )z;
        find an available port for TCP connection
        r      zFound available port %d)socketbindrk   getsocknamecloser   r   )rx   sockr   s      r   rd   zSlapdObject._avail_tcp_port=  s     }	IIt*+++##%%a(DJJLLLLDJJLLLL	0$777s   6A   A6c                     t          | j                  | j        | j        | j        | j        | j        | j        t          j	                    t          j
                    | j        | j        | j        d}| j        |z  S )z
        generates a slapd.conf and returns it as one string

        for generating specific static configuration files you have to
        override this method
        )serveridlogleveldatabase	directorysuffixrootdnrootpwroot_uidroot_gidrs   rt   ru   )hexrf   slapd_loglevelr   rj   r   r~   root_pwr   getuidgetgidrs   rt   ru   slapd_conf_template)rx   config_dicts     r   
gen_configzSlapdObject.gen_configJ  sn     DN++++kll		k/
 
 '+55r   c                     |D ]V}t           j                            | j        |          }| j                            d|           t          j        |           WdS )z@
        create sub-directories beneath self.testrundir
        zCreate directory %sN)r   r6   r5   rh   r   r   r   )rx   	dir_namesdnamedir_names       r   r   zSlapdObject._create_sub_dirsa  s^      	 	Ew||DOU;;HIOO18<<<HX	 	r   c                 <     j                             d j                                                                         dg            fd j        D             }|D ]}                     ddd|g            j                             d j                   dS )z Loads the slapd.d configuration.zimporting configuration: %sz-n0c                     g | ]H}t           j                            |          r|n$t           j                            j        |          IS r   )r   r6   rD   r5   rq   ).0schemarx   s     r   
<listcomp>z-SlapdObject._write_config.<locals>.<listcomp>o  sW     
 
 
  w~~f%%6FFdnf55
 
 
r   Nz-lzimport ok: %s)r   r   ri   r   r   openldap_schema_files)rx   
ldif_paths	ldif_paths   `  r   _write_configzSlapdObject._write_configj  s    	5t7GHHHT__&&000
 
 
 
 4	
 
 

 $ 	9 	9ILLtY78888	)9:::::r   c                    | j                             d| j                   | j        dd| j        ddddg}t	          j        |t          j        t          j                  }|j        d	k    rA| j         	                    |j
                            d
                     t          d          | j                             d| j                   d S )Nztesting config %sz-Ttest-Fz-uz-v-dconfig)stdoutstderrr   utf-8zconfiguration test failedzconfig ok: %s)r   r   ri   r   
subprocessrunPIPESTDOUT
returncodeerrorr   decodeRuntimeErrorr   )rx   
popen_listps      r   _test_configzSlapdObject._test_configz  s    	+T-=>>>O$"(

 N?$
 
 

 <1IOOAHOOG44555:;;;	(899999r   c                 ~   | j         g}| j        r|                    | j                   | j        d| j        dd                    |          g}| j                            t          j	                  r|
                    ddg           n|
                    ddg           | j                            dd                    |                     t          j        |          | _        t          j                    dz   }	 | j                                        #|                                  t'          d          	 | j                            d| j                   |                                  d
S # t&          $ r0 t          j                    |k    rY nt          j        d           Y nw xY wt'          d          )z0
        Spawns/forks the slapd process
        r   z-hr<   r   z-10zstarting slapd: %r
   TNz slapd exited before opening portzslapd connection check to %sg?zslapd did not start properly)rl   rm   r4   r   ri   r5   r   isEnabledForrB   DEBUGextendr   r   Popenrc   time	monotonicpoll_stoppedr   r   rn   r   sleep)rx   urls
slapd_argsdeadlines       r   _start_slapdzSlapdObject._start_slapd  s    > 	(KK'''O$"#((4..


 9!!'-00 	+tTl++++tSk***	+SXXj-A-ABBB%j11
>##b(	z  ,"#EFFF
	2D4I   !!!         >##x//E
3 	 9:::s   <4E2 2!F,F,+F,c                 t   | j         t          j        | j                   |                                  |                                  |                                  |                                  |                                  | j	        
                    d| j         j        | j        | j                   dS dS )zW
        Starts the slapd server process running, and waits for it to come up.
        Nz(slapd with pid=%d listening on %s and %s)rc   atexitregisterstopr   r   r   r   r   r   r   pidrl   rm   r|   s    r   startzSlapdObject.start  s    
 :ODI&&&  """   IOO:
t~     r   c                    | j         R| j                            d| j         j                   | j                                          |                                  |                                  t          j        | j	                   dS )zU
        Stops the slapd server, and waits for it to terminate and cleans up
        Nzstopping slapd with pid %d)
rc   r   r   r   	terminatewaitr   r   
unregisterr   r|   s    r   r   zSlapdObject.stop  ss     :!IOO8$*.IIIJ  """IIKKK$)$$$$$r   c                     | j                                          |                                  |                                  dS )z:
        Restarts the slapd server with same data
        N)rc   r   r   r   r|   s    r   restartzSlapdObject.restart  s=     	
		r   c                 r    | j         r/| j                                          |                                  dS dS )z3Waits for the slapd process to terminate by itself.N)rc   r   r   r|   s    r   r   zSlapdObject.wait  s9    : 	JOOMMOOOOO	 	r   c                 p    | j         .| j                            d| j         j                   d| _         dS dS )z8Called when the slapd server is known to have terminatedNzslapd[%d] terminated)rc   r   r   r   r|   s    r   r   zSlapdObject._stopped  s8    :!INN14:>BBBDJJJ "!r   c                     | j         r>ddg}| j                            t          j                  s|                    d           ndd| j        d| j        g}|S )Nz-YEXTERNALz-Qz-xz-Dz-w)ro   r   r   rB   r   r4   r~   r   )rx   
authc_argss     r   _cli_auth_argszSlapdObject._cli_auth_args  sl    ! 	jJ 9))'-88 (!!$''' dldlJ
 r   c                    || j         }|                    d          d                             d          r|d|g|                                 z   }n
|d| j        g}||pg z  }| j                            dd                    |                     t          j	        |t          j
        t          j
        t          j
                  }| j                            d	|           |                    |          \  }}|| j                            d
|           || j                            d|           |                                dk    r$t          d                    |||                    ||fS )N/r    z-Hr   zRun command: %rr<   )stdinr   r   zstdin_data=%rzstdout_data=%rzstderr_data=%rr   z{!r} process failed:
{!r}
{!r})rn   r0   
startswithr  ri   r   r   r5   r   r   r   communicater   r   r}   )	rx   ldapcommand
extra_argsrl   
stdin_dataargsprocstdout_datastderr_datas	            r   
_cli_popenzSlapdObject._cli_popen  st   ,HS!!"%0088 	9x043F3F3H3HHDDt'78D!r"	)388D>>:::

?
 
 
 		444#'#3#3J#?#? ["IOO,k:::"IOO,k:::99;;!299+{   
 K''r   c                 >    |                      | j        |           dS )z8
        Runs ldapwhoami on this slapd instance
        r  N)r  r   )rx   r  s     r   r   zSlapdObject.ldapwhoami  s#     	,DDDDDr   c                 f    |                      | j        ||                    d                     dS zR
        Runs ldapadd on this slapd instance, passing it the ldif content
        r   )r  r  N)r  r   encoderx   ldifr  s      r   r   zSlapdObject.ldapadd  s?     	)j#';;w#7#7 	 	9 	9 	9 	9 	9r   c                 f    |                      | j        ||                    d                     dS r  )r  r   r  r  s      r   r   zSlapdObject.ldapmodify"  s?     	,#';;w#7#7 	 	9 	9 	9 	9 	9r   c                     |g }|r|                     d           |                     |           |                     | j        |           dS )zG
        Runs ldapdelete on this slapd instance, deleting 'dn'
        Nz-rr  )r4   r  r   )rx   dn	recursiver  s       r   r   zSlapdObject.ldapdelete)  s^     J 	$d###",DDDDDr   c                 n    |                      | j        |r|                    d          nd|           dS )zR
        Runs slapadd on this slapd instance, passing it the ldif content
        r   N)r  r  )r  r   r  r  s      r   r   zSlapdObject.slapadd4  sK     	/3=t{{7+++! 	 	
 	
 	
 	
 	
r   c                 .    |                                   | S r   )r   r|   s    r   	__enter__zSlapdObject.__enter__>  s    

r   c                 .    |                                   d S r   )r   )rx   exc_type	exc_value	tracebacks       r   __exit__zSlapdObject.__exit__B  s    		r   )F)NNNr   )FN):__name__
__module____qualname____doc__SLAPD_CONF_TEMPLATEr   r   r   root_cnr   r   	LOCALHOSTrk   r   r   r   r   r   getcwdrg   rq   r6   isdirdefpathr   r9   r   rU   r   rz   propertyr~   r   r   rp   r   r   r   rd   r   r   r   r   r   r   r   r  r   r   r  r  r   r   r   r   r   r#  r(  r   r   r   rW   rW      s.        * .H2FGG#NJN Z^^E929;;//F2:Jx(			-	.	. *			)	*	* &			z~~eRZ^^FBJ%G%GHHH
vyy':':;;I ?-..D@ @ @@ C C XC   X   X	H 	H 	H   	3 	3 	39 9 9.  6 6 6.  ; ; ; : : :(%; %; %;N  $	% 	% 	%          AE"( ( ( (>E E E E9 9 9 99 9 9 9	E 	E 	E 	E
 
 
 
      r   rW   c                   R    e Zd ZdZeZdZdZddZe	d             Z
e	d             ZdS )SlapdTestCasezE
    test class which also clones or initializes a running slapd
    Nc                      | j         | j        j        fi |}d|_        |                    |p| j        j        |p| j        j                   |S )z@
        return a LDAPObject instance after simple bind
           )ldap_object_classserverrl   protocol_versionsimple_bind_sr~   r   )rx   whocredkwargs	ldap_conns        r   _open_ldap_connzSlapdTestCase._open_ldap_connO  s[     +D*4;+?JJ6JJ	%&	" :t{':D<WDKDWXXXr   c                 j    |                                  | _        | j                                         d S r   )server_classr9  r   clss    r   
setUpClasszSlapdTestCase.setUpClassY  s/    %%''

r   c                 8    | j                                          d S r   )r9  r   rC  s    r   tearDownClasszSlapdTestCase.tearDownClass^  s    
r   )NN)r)  r*  r+  r,  rW   rB  r9  r8  r@  classmethodrE  rG  r   r   r   r5  r5  F  sz          LF      [   [  r   r5  r   )*r,  r   r   r2   r   r   rB   r   logging.handlersr   r   shutilr   urllib.parser   r   r    r6   abspathr   __file__rr   r-  r/  setr   r0   r   r(   hasattrr   r   r"   r&   r)   r-   r9   WARNrU   rW   TestCaser5  r   r   r   <module>rR     s!   
 
			  



        * * * * * *        # # # # # # 
<  	wrwx0011 8 	c"*..3399#>>??
kJJ++J  	 	 	 	        ( ( ( ,2B	! ! ! !Hb b b b b b b bJ    H%     r   