The library leverages the pytest framework for organizing and marking test cases, tox to automate the process of running them across supported Python versions, and coverage to obtain coverage statistics.
Some test cases are "local", meaning that don't require a target environment and can be run off-line, while the bulk of the test cases are "remote" and requires some prior setup.
If you want to run the full set of library test cases, you need to prepare your environment by completing the following steps:
-
Install testing requirements. You can use the following command to do so:
python3 -m pip install tox -r requirements-test.txt
-
Install and configure a target Active Directory Domain Controller.
Important note
Bear in mind that some remote tests are not idempotent, that means that they perform changes on the target environment and the results of the tests depends on that. As an example, some tests require the creation/modification/deletion of user accounts. If those tests fail at some point during the process, user accounts might lay down there and subsequent tests might fail when trying to create the user account. We recommend taking snapshots of the target environment that can be then rolled back after a testing session.
Once that's done, you would be able to run the test suite with pytest
. For example,
you can run all "local" test cases using the following command:
$ pytest -m "not remote"
Or run the "remote" test cases with the following command:
$ pytest -m "remote"
If all goes well, all test cases should pass.
You can also leverage pytest
markers
or keyword expressions
to select which test case you want to run. Although we recommend using pytest
, it's also possible to run individual test
case modules via unittest.main
method. For example, to only run ldap
test cases,
you can execute:
$ pytest -k "ldap"
If you want to run the test cases in a new fresh environment, or run those across
different Python versions, you can use tox
. You can specify the group of test cases
you want to run, which would be passed to pytest
. As an example, the following
command will run all "local" test cases across all the Python versions defined in
the tox
configuration:
$ tox -- -m "not remote"
If you want to measure coverage in your test cases run, you can use it via the
pytest-cov
plugin, for example by running the following command:
$ pytest --cov --cov-config=tox.ini
tox
will collect and report coverage statistics as well, and combine it across
different Python version environment runs. You will have a coverage HTML report
located at the default Coverage
's location htlmcov/index.html
.
Configuration of all pytest
, coverage
and tox
is contained in the
tox.ini file. Refer to each tool documentation for further details
about the different settings.
In order to run remote test cases, a target Active Directory need to be properly configured with the expected objects. Current remote test cases are expected to work against a Windows Server 2012 R2 Domain Controller. The following are the main steps required:
-
Make sure to disable the firewall on the interface you want to use for connecting to the Domain Controller.
PS C:\> Set-NetFirewallProfile -Profile Domain, Public, Private -Enabled False
-
Install the Active Directory Domain Services on the target server.
PS C:\> Install-WindowsFeature -name AD-Domain-Services -IncludeManagementTools
-
Make sure the server's Administrator user password meet the complexity policy, as it's required for promoting it to Domain Controller.
PS C:\> $AdminPassword = "<Admin Password>" PS C:\> $Admin=[adsi]("WinNT://$env:COMPUTERNAME/Administrator, user") PS C:\> $Admin.psbase.invoke("setpassword", $AdminPassword)
-
Promote the installed Windows Server 2012 R2 to a Domain Controller, and configure a domain of your choice.
PS C:\> $DomainName = "<Domain Name>" PS C:\> $NetBIOSName = "<NetBIOS Name>" PS C:\> $RecoveryPassword = "<Recovery Password>" PS C:\> $SecureRecoveryPassword = ConvertTo-SecureString $RecoveryPassword -AsPlainText -Force PS C:\> Install-ADDSForest -DomainName $DomainName -InstallDns -SafeModeAdministratorPassword $SecureRecoveryPassword -DomainNetbiosName $NetBIOSName -SkipPreChecks
-
Install DHCP services on the target Domain Controller.
PS C:\> Install-WindowsFeature -name DHCP -IncludeManagementTools
-
Create the DHCP administration groups and authorize the server.
PS C:\> netsh dhcp add securitygroups PS C:\> Restart-Service dhcpserver PS C:\> Add-DhcpServerInDC -DnsName <Server Name> -IPAddress <IP Address> PS C:\> $Credential = Get-Credential PS C:\> Set-DhcpServerDnsCredential -Credential $Credential -ComputerName <Server Name>
-
Be sure to enable and run the
RemoteRegistry
service on the target Domain Controller.PS C:\> Start-Service RemoteRegistry
-
Create a Domain User with administrative rights. This is the user that will be used to run the remote tests. We make sure to enable AES Kerberos encryption type and add it to the Domain Admins group.
PS C:\> $AdminUserName = "<Admin User Name>" PS C:\> $AdminAccountName = "<Admin Account Name>" PS C:\> $AdminUserPassword = "<Admin User Password>" PS C:\> $SecureAdminUserPassword = ConvertTo-SecureString $AdminUserPassword -AsPlainText -Force PS C:\> New-ADUser -Name $AdminUserName -SamAccountName $AdminAccountName -UserPrincipalName $AdminAccountName@$DomainName -AccountPassword $SecureAdminUserPassword -Enabled $true -ChangePasswordAtLogon $false -KerberosEncryptionType RC4,AES128,AES256 PS C:\> Add-ADGroupMember -Identity "Domain Admins" -Members <Account Name>
For running LDAPS (LDAP over SSL/TLS) test cases, make sure you have a certificate installed and configured on the target Domain Controller. You can follow Microsoft's guidelines to configure LDAPS.
You can use self-signed certificates by:
-
Create a CA private key and certificate:
$ openssl genrsa -aes256 -out ca_private.key 4096 $ openssl req -new -x509 -days 3650 -key ca_private.key -out ca_public.crt
-
Copying and importing the CA public certificate into the Domain Controller server:
PS C:\> Import-Certificate -FilePath ca_public.crt -CertStoreLocation 'Cert:\LocalMachine\Root' -Verbose
-
Creating a certificate request for the LDAP service, by editing the following configuration file:
;----------------- request.inf ----------------- [Version] Signature="$Windows NT$ [NewRequest] Subject = "CN=<DC fqdn>" ; replace with the FQDN of the DC KeySpec = 1 KeyLength = 1024 Exportable = TRUE MachineKeySet = TRUE SMIME = False PrivateKeyArchive = FALSE UserProtected = FALSE UseExistingKeySet = FALSE ProviderName = "Microsoft RSA SChannel Cryptographic Provider" ProviderType = 12 RequestType = PKCS10 KeyUsage = 0xa0 [EnhancedKeyUsageExtension] OID=1.3.6.1.5.5.7.3.1 ; this is for Server Authentication ;-----------------------------------------------
And then running the following command:
PS C:\> certreq -new request.inf ldapcert.csr
-
Signing the LDAP service certificate with the CA, by creating the
v3ext.txt
configuration file:keyUsage=digitalSignature,keyEncipherment extendedKeyUsage=serverAuth subjectKeyIdentifier=hash
And running the following command:
$ openssl x509 -req -days 365 -in ldapcert.csr -CA ca_public.crt -CAkey ca_private.key -extfile v3ext.txt -set_serial 01 -out ldapcert.crt
-
Copying and installing the new signed LDAP service certificate into the Domain Controller server:
PS C:\> certreq -accept ldapcert.crt
-
Finally, restarting the Domain Controller.
Mimilib test cases require the service to be installed on the target Domain Controller. You can do that by running Mimikatz with an elevated user and executing:
mimikatz # rpc::server
Create a copy of the dcetest.cfg.template file and configure it with the necessary information associated to the Active Directory you configured. Path to the configuration file to use when running tests can be then specified in the following ways:
- Using the pytest
--remote-config
command-line option. - Using the pytest
remote-config
option intox.ini
. - Using the
REMOTE_CONFIG
environment variable. - Default to loading from
tests/dcetests.cg
.
For example, you can keep configuration of different environments in separate files, and specify which one you want the test to run against:
$ pytest --remote-config=tests/dcetests-win2016.cfg
$ pytest --remote-config=tests/dcetests-win2019.cfg
Make sure you set a user with proper administrative privileges on the target Active Directory domain and that the user hashes and keys match with those in the environment. Hashes and Kerberos keys can be grabbed from the target Domain Controller using secretsdump.py example script.
Make sure also to have full network visibility into the target hosts and be able to
resolve DNS queries for the Active Directory Domain configured. If you don't want to
change your test machine's DNS settings to point to the AD DNS server, you can
configure your system to statically resolve (e.g. via /etc/hosts
file) the host
and domain FQDN to the server's IP address.