File diff f7c1f4c841f8 → c2f446ec7e2a
roles/mail_server/molecule/default/tests/test_optional.py
Show inline comments
 
@@ -3,6 +3,10 @@ import re
 
import time
 
import uuid
 

	
 
import defusedxml.ElementTree as ElementTree
 

	
 
import pytest
 

	
 
import testinfra.utils.ansible_runner
 

	
 

	
 
@@ -129,12 +133,11 @@ def test_mail_owner(host):
 
    assert user.groups == ["virtmail"]
 

	
 

	
 
def test_imap_tls_configuration(host):
 
def test_imap_tls_connectivity(host):
 
    """
 
    Tests TLS configuration for IMAP in Dovecot.
 
    Tests connectivity over STARTTLS/TLS towards IMAP server.
 
    """
 

	
 
    # Test plain connectivity first.
 
    starttls = host.run('echo "a0001 LOGOUT" | openssl s_client -quiet -starttls imap -connect parameters-optional:143')
 
    assert starttls.rc == 0
 
    assert '* BYE Logging out' in starttls.stdout
 
@@ -143,40 +146,53 @@ def test_imap_tls_configuration(host):
 
    assert tls.rc == 0
 
    assert '* BYE Logging out' in starttls.stdout
 

	
 
    # Test TLS protocol versions.
 
    starttls = host.run('echo "a0001 LOGOUT" | openssl s_client -quiet -starttls imap -no_tls1_2 -connect parameters-optional:143')
 
    assert starttls.rc == 0
 
    assert '* BYE Logging out' in starttls.stdout
 

	
 
    tls = host.run('echo "a0001 LOGOUT" | openssl s_client -quiet -no_tls1_2 -connect parameters-optional:993')
 
    assert tls.rc == 0
 
    assert '* BYE Logging out' in starttls.stdout
 
@pytest.mark.parametrize("port", [
 
    143,
 
    993,
 
    587,
 
])
 
def test_imap_and_smtp_submission_tls_version_and_ciphers(host, port):
 
    """
 
    Tests if the correct TLS version and ciphers have been enabled for
 
    IMAP and SMTP submission.
 
    """
 

	
 
    expected_tls_versions = ["TLSv1.1", "TLSv1.2"]
 

	
 
    expected_tls_ciphers = [
 
        "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256",
 
        "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256",
 
        "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256",
 
        "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384",
 
        "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
 
        "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
 
        "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
 
        "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384",
 
        "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
 
    ]
 

	
 
    starttls = host.run("echo 'a0001 LOGOUT' | openssl s_client -quiet -starttls imap -no_tls1_1 -no_tls1_2 -connect parameters-optional:143")
 
    assert starttls.rc != 0
 
    assert 'SSL alert number 70' in starttls.stderr
 
    # Run the nmap scanner against the server, and fetch the results.
 
    nmap = host.run("nmap -sV --script ssl-enum-ciphers -p %s localhost -oX /tmp/report.xml", str(port))
 
    assert nmap.rc == 0
 
    report_content = host.file('/tmp/report.xml').content_string
 

	
 
    tls = host.run("echo 'a0001 LOGOUT' | openssl s_client -quiet -no_tls1_1 -no_tls1_2 -connect parameters-optional:993")
 
    assert tls.rc != 0
 
    assert 'SSL alert number 70' in tls.stderr
 
    report_root = ElementTree.fromstring(report_content)
 

	
 
    # Test at least one strong TLS cipher.
 
    starttls_cipher = host.run("echo 'a0001 LOGOUT' | openssl s_client -starttls imap -cipher ECDHE-RSA-AES128-SHA256 -connect parameters-optional:143")
 
    assert starttls_cipher.rc == 0
 
    assert "ECDHE-RSA-AES128-SHA256" in starttls_cipher.stdout
 
    tls_versions = []
 
    tls_ciphers = set()
 

	
 
    tls_cipher = host.run("echo 'a0001 LOGOUT' | openssl s_client -cipher ECDHE-RSA-AES128-SHA256 -connect parameters-optional:993")
 
    assert tls_cipher.rc == 0
 
    assert "ECDHE-RSA-AES128-SHA256" in tls_cipher.stdout
 
    for child in report_root.findall("./host/ports/port/script/table"):
 
        tls_versions.append(child.attrib['key'])
 

	
 
    # Test weaker TLS cipher that was explicitly configured
 
    starttls_cipher = host.run("echo 'a0001 LOGOUT' | openssl s_client -starttls imap -cipher ECDHE-RSA-AES128-SHA -connect parameters-optional:143")
 
    assert starttls_cipher.rc == 0
 
    assert "ECDHE-RSA-AES128-SHA" in starttls_cipher.stdout
 
    for child in report_root.findall(".//table[@key='ciphers']/table/elem[@key='name']"):
 
        tls_ciphers.add(child.text)
 

	
 
    tls_cipher = host.run("echo 'a0001 LOGOUT' | openssl s_client -cipher ECDHE-RSA-AES128-SHA -connect parameters-optional:993")
 
    assert tls_cipher.rc == 0
 
    assert "ECDHE-RSA-AES128-SHA" in tls_cipher.stdout
 
    tls_versions.sort()
 
    tls_ciphers = sorted(list(tls_ciphers))
 

	
 
    assert tls_versions == expected_tls_versions
 
    assert tls_ciphers == expected_tls_ciphers
 

	
 

	
 
def test_dovecot_postmaster(host):
 
@@ -205,54 +221,106 @@ def test_imap_max_user_connections_per_ip(host):
 
        assert "  mail_max_userip_connections = 2" in config.stdout
 

	
 

	
 
def test_postfix_tls_configuration(host):
 
def test_smtp_tls_connectivity(host):
 
    """
 
    Tests TLS configuration for SMTP in Postfix.
 
    Tests connectivity over default/submission port towards SMTP
 
    server.
 
    """
 

	
 
    # Test TLS protocol versions for default port (all should be enabled).
 
    starttls = host.run("echo 'QUIT' | openssl s_client -quiet -starttls smtp -no_tls1 -no_tls1_1 -connect parameters-optional:25")
 
    assert starttls.rc == 0
 
    assert '221 2.0.0 Bye' in starttls.stdout
 

	
 
    starttls = host.run("echo 'QUIT' | openssl s_client -quiet -starttls smtp -no_tls1_2 -connect parameters-optional:25")
 
    assert starttls.rc == 0
 
    assert '221 2.0.0 Bye' in starttls.stdout
 

	
 
    starttls = host.run("echo 'QUIT' | openssl s_client -quiet -starttls smtp -no_tls1_2 -no_tls1_1 -connect parameters-optional:25")
 
    assert starttls.rc == 0
 
    assert '221 2.0.0 Bye' in starttls.stdout
 

	
 
    # Test TLS protocol versions for submission port (only TLS 1.1 and TLS 1.2 should be enabled).
 
    starttls = host.run("echo 'QUIT' | openssl s_client -quiet -starttls smtp -connect parameters-optional:587")
 
    starttls = host.run('echo "QUIT" | openssl s_client -quiet -starttls smtp -connect parameters-optional:25')
 
    assert starttls.rc == 0
 
    assert '221 2.0.0 Bye' in starttls.stdout
 

	
 
    starttls = host.run("echo 'QUIT' | openssl s_client -quiet -starttls smtp -no_tls1_2 -connect parameters-optional:587")
 
    assert starttls.rc == 0
 
    tls = host.run('echo "QUIT" | openssl s_client -quiet -starttls smtp -connect parameters-optional:587')
 
    assert tls.rc == 0
 
    assert '221 2.0.0 Bye' in starttls.stdout
 

	
 
    starttls = host.run("echo 'QUIT' | openssl s_client -quiet -starttls smtp -no_tls1_1 -no_tls1_2 -connect parameters-optional:587")
 
    assert starttls.rc != 0
 
    assert 'SSL alert number 70' in starttls.stderr
 

	
 
    # Test ciphers for default port (less restrictive).
 
    starttls_cipher = host.run("echo 'QUIT' | openssl s_client -starttls smtp -cipher ECDHE-RSA-AES128-SHA256 -connect parameters-optional:25")
 
    assert starttls_cipher.rc == 0
 
    assert "ECDHE-RSA-AES128-SHA256" in starttls_cipher.stdout
 

	
 
    starttls_cipher = host.run("echo 'QUIT' | openssl s_client -starttls smtp -cipher ECDHE-RSA-AES128-SHA -connect parameters-optional:25")
 
    assert starttls_cipher.rc == 0
 
    assert "ECDHE-RSA-AES128-SHA" in starttls_cipher.stdout
 

	
 
    # Test ciphers for submission port (at least one weak cipher was configured).
 
    starttls_cipher = host.run("echo 'QUIT' | openssl s_client -starttls smtp -cipher ECDHE-RSA-AES128-SHA256 -connect parameters-optional:587")
 
    assert starttls_cipher.rc == 0
 
    assert "ECDHE-RSA-AES128-SHA256" in starttls_cipher.stdout
 
def test_smtp_default_port_tls_version_and_ciphers(host):
 
    """
 
    Tests TLS configuration for SMTP default port (needs to be less
 
    restrictive for interoperability purposes).
 
    """
 

	
 
    starttls_cipher = host.run("echo 'QUIT' | openssl s_client -starttls smtp -cipher ECDHE-RSA-AES128-SHA -connect parameters-optional:587")
 
    assert starttls_cipher.rc == 0
 
    assert "ECDHE-RSA-AES128-SHA" in starttls_cipher.stdout
 
    expected_tls_versions = ["TLSv1.0", "TLSv1.1", "TLSv1.2"]
 

	
 
    expected_tls_ciphers = [
 
        "TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
 
        "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256",
 
        "TLS_DHE_RSA_WITH_AES_128_CCM",
 
        "TLS_DHE_RSA_WITH_AES_128_CCM_8",
 
        "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256",
 
        "TLS_DHE_RSA_WITH_AES_256_CBC_SHA",
 
        "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256",
 
        "TLS_DHE_RSA_WITH_AES_256_CCM",
 
        "TLS_DHE_RSA_WITH_AES_256_CCM_8",
 
        "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384",
 
        "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA",
 
        "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256",
 
        "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA",
 
        "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256",
 
        "TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
 
        "TLS_DHE_RSA_WITH_SEED_CBC_SHA",
 
        "TLS_DH_anon_WITH_AES_128_CBC_SHA",
 
        "TLS_DH_anon_WITH_AES_128_CBC_SHA256",
 
        "TLS_DH_anon_WITH_AES_128_GCM_SHA256",
 
        "TLS_DH_anon_WITH_AES_256_CBC_SHA",
 
        "TLS_DH_anon_WITH_AES_256_CBC_SHA256",
 
        "TLS_DH_anon_WITH_AES_256_GCM_SHA384",
 
        "TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA",
 
        "TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256",
 
        "TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA",
 
        "TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256",
 
        "TLS_DH_anon_WITH_SEED_CBC_SHA",
 
        "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
 
        "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
 
        "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
 
        "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
 
        "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384",
 
        "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
 
        "TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256",
 
        "TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384",
 
        "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
 
        "TLS_ECDH_anon_WITH_AES_128_CBC_SHA",
 
        "TLS_ECDH_anon_WITH_AES_256_CBC_SHA",
 
        "TLS_RSA_WITH_AES_128_CBC_SHA",
 
        "TLS_RSA_WITH_AES_128_CBC_SHA256",
 
        "TLS_RSA_WITH_AES_128_CCM",
 
        "TLS_RSA_WITH_AES_128_CCM_8",
 
        "TLS_RSA_WITH_AES_128_GCM_SHA256",
 
        "TLS_RSA_WITH_AES_256_CBC_SHA",
 
        "TLS_RSA_WITH_AES_256_CBC_SHA256",
 
        "TLS_RSA_WITH_AES_256_CCM",
 
        "TLS_RSA_WITH_AES_256_CCM_8",
 
        "TLS_RSA_WITH_AES_256_GCM_SHA384",
 
        "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA",
 
        "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256",
 
        "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA",
 
        "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256",
 
        "TLS_RSA_WITH_SEED_CBC_SHA",
 
    ]
 

	
 
    # Run the nmap scanner against the server, and fetch the results.
 
    nmap = host.run("nmap -sV --script ssl-enum-ciphers -p 25 localhost -oX /tmp/report.xml")
 
    assert nmap.rc == 0
 
    report_content = host.file('/tmp/report.xml').content_string
 

	
 
    report_root = ElementTree.fromstring(report_content)
 

	
 
    tls_versions = []
 
    tls_ciphers = set()
 

	
 
    for child in report_root.findall("./host/ports/port/script/table"):
 
        tls_versions.append(child.attrib['key'])
 

	
 
    for child in report_root.findall(".//table[@key='ciphers']/table/elem[@key='name']"):
 
        tls_ciphers.add(child.text)
 

	
 
    tls_versions.sort()
 
    tls_ciphers = sorted(list(tls_ciphers))
 

	
 
    assert tls_versions == expected_tls_versions
 
    assert tls_ciphers == expected_tls_ciphers
 

	
 

	
 
def test_sieve_tls_configuration(host):