Changeset - 17cf34f73ca6
[Not reviewed]
0 5 4
Branko Majic (branko) - 7 years ago 2017-07-04 23:21:50
branko@majic.rs
MAR-28: Implemented additional tests for mail_server role:

- Deploy a number of tools on clients in order to test SMTP, IMAP, and Sieve
services.
- Added one more user to LDAP directory for testing group restrictions.
- Deploy CA certificate on all testing machines for TLS validation purposes.
- Use different custom-configured cipher for mail server ciphers.
- Fixed invalid postmaster address for parameters-optional host.
- Deploy configuration files for use with Imap-CLI on client test machines.
- Updated testing of SMTP server to include checks for users that do not belong
to mail group.
- Extended some SMTP-related tests to cover both test servers.
- Some small fixes in SMTP-related tests for expected output from commands.
- Implemented tests covering Dovecot (IMAP + Sieve) functionality.
- Implemented tests for running/enabled services.
- Implemented tests for ClamAV.
- Implemented tests for firewall and connectivity.
- Implemented tests for Postfix TLS configuration.
- TODO: Tests for Sieve TLS configuration have not been written yet due to
limitation of available tools.
9 files changed with 761 insertions and 5 deletions:
0 comments (0 inline, 0 general)
roles/mail_server/playbook.yml
Show inline comments
 
@@ -29,6 +29,54 @@
 
        name: swaks
 
        state: installed
 

	
 
    - name: Install pip
 
      apt:
 
        name: python-pip
 
        state: installed
 

	
 
    - name: Install IMAP CLI tool
 
      pip:
 
        name: Imap-CLI==0.6
 
        state: present
 

	
 
    - name: Install tool for testing SIEVE
 
      apt:
 
        name: sieve-connect
 
        state: installed
 

	
 
    - name: Install tool for testing TCP connectivity
 
      apt:
 
        name: hping3
 
        state: installed
 

	
 
    - name: Deploy IMAP CLI configuration
 
      copy:
 
        src: "tests/data/{{ item }}"
 
        dest: "/home/vagrant/{{ item }}"
 
        owner: vagrant
 
        group: vagrant
 
        mode: 0600
 
      with_items:
 
        - imapcli-parameters-mandatory-john_doe.conf
 
        - imapcli-parameters-mandatory-jane_doe.conf
 
        - imapcli-parameters-optional-john_doe.conf
 
        - imapcli-parameters-optional-jane_doe.conf
 

	
 
    - name: Deploy CA certificate
 
      copy:
 
        src: tests/data/x509/ca.cert.pem
 
        dest: /usr/local/share/ca-certificates/testca.crt
 
        owner: root
 
        group: root
 
        mode: 0644
 
      notify:
 
        - Update CA certificate cache
 

	
 
  handlers:
 

	
 
    - name: Update CA certificate cache
 
      command: /usr/sbin/update-ca-certificates --fresh
 

	
 
- hosts: ldap-server
 
  roles:
 
    - role: ldap_server
 
@@ -57,6 +105,17 @@
 
            sn: Doe
 
            mail: jane.doe@domain2
 

	
 
        - dn: uid=nomail,ou=people,dc=local
 
          attributes:
 
            objectClass:
 
              - inetOrgPerson
 
              - simpleSecurityObject
 
            userPassword: nomailpassword
 
            uid: nomail
 
            cn: No Mail
 
            sn: Mail
 
            mail: nomail@domain1
 

	
 
        # Groups
 
        - dn: "cn=mail,ou=groups,dc=local"
 
          state: append
 
@@ -134,6 +193,10 @@
 
      tls_certificate_dir: tests/data/x509/
 
      tls_private_key_dir: tests/data/x509/
 

	
 
      # common
 
      ca_certificates:
 
        testca: "{{ lookup('file', 'tests/data/x509/ca.cert.pem') }}"
 

	
 
- hosts: parameters-optional
 
  roles:
 
    - role: mail_server
 
@@ -145,7 +208,7 @@
 
      mail_server_tls_protocols:
 
        - TLSv1.2
 
        - TLSv1.1
 
      mail_server_tls_ciphers: "DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:DHE-RSA-AES256-SHA:!aNULL:!MD5:!EXPORT"
 
      mail_server_tls_ciphers: "DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:!aNULL:!MD5:!EXPORT"
 
      mail_user: virtmail
 
      mail_user_uid: 5000
 
      mail_user_gid: 5000
 
@@ -161,6 +224,10 @@
 
        - bl.spamcop.net
 
        - zen.spamhaus.org
 

	
 
      mail_postmaster: "webmaster@parameters-optional.local"
 
      mail_postmaster: "webmaster@parameters-optional"
 
      smtp_allow_relay_from:
 
        - 10.31.127.20
 

	
 
      # common
 
      ca_certificates:
 
        testca: "{{ lookup('file', 'tests/data/x509/ca.cert.pem') }}"
roles/mail_server/tests/data/imapcli-parameters-mandatory-jane_doe.conf
Show inline comments
 
new file 100644
 
[imap]
 
hostname = parameters-mandatory
 
username = jane.doe@domain2
 
password = janepassword
 
ssl = True
 

	
 
[display]
 
format_list =
 
    ID:         {uid}
 
    Flags:      {flags}
 
    From:       {from}
 
    To:         {to}
 
    Date:       {date}
 
    Subject:    {subject}
 
format_thread = {uid} {subject} <<< FROM {from}
 
format_status = {directory:>20} : {count:>5} Mails - {unseen:>5} Unseen - {recent:>5} Recent
 
limit = 10
 

	
 
[trash]
 
# delete method can be : MOVE_TO_TRASH, FLAG or EXPUNGE
 
delete_method = MOVE_TO_TRASH
 
trash_directory = Trash
roles/mail_server/tests/data/imapcli-parameters-mandatory-john_doe.conf
Show inline comments
 
new file 100644
 
[imap]
 
hostname = parameters-mandatory
 
username = john.doe@domain1
 
password = johnpassword
 
ssl = True
 

	
 
[display]
 
format_list =
 
    ID:         {uid}
 
    Flags:      {flags}
 
    From:       {from}
 
    To:         {to}
 
    Date:       {date}
 
    Subject:    {subject}
 
format_thread = {uid} {subject} <<< FROM {from}
 
format_status = {directory:>20} : {count:>5} Mails - {unseen:>5} Unseen - {recent:>5} Recent
 
limit = 10
 

	
 
[trash]
 
# delete method can be : MOVE_TO_TRASH, FLAG or EXPUNGE
 
delete_method = MOVE_TO_TRASH
 
trash_directory = Trash
roles/mail_server/tests/data/imapcli-parameters-optional-jane_doe.conf
Show inline comments
 
new file 100644
 
[imap]
 
hostname = parameters-optional
 
username = jane.doe@domain2
 
password = janepassword
 
ssl = True
 

	
 
[display]
 
format_list =
 
    ID:         {uid}
 
    Flags:      {flags}
 
    From:       {from}
 
    To:         {to}
 
    Date:       {date}
 
    Subject:    {subject}
 
format_thread = {uid} {subject} <<< FROM {from}
 
format_status = {directory:>20} : {count:>5} Mails - {unseen:>5} Unseen - {recent:>5} Recent
 
limit = 10
 

	
 
[trash]
 
# delete method can be : MOVE_TO_TRASH, FLAG or EXPUNGE
 
delete_method = MOVE_TO_TRASH
 
trash_directory = Trash
roles/mail_server/tests/data/imapcli-parameters-optional-john_doe.conf
Show inline comments
 
new file 100644
 
[imap]
 
hostname = parameters-optional
 
username = john.doe@domain1
 
password = johnpassword
 
ssl = True
 

	
 
[display]
 
format_list =
 
    ID:         {uid}
 
    Flags:      {flags}
 
    From:       {from}
 
    To:         {to}
 
    Date:       {date}
 
    Subject:    {subject}
 
format_thread = {uid} {subject} <<< FROM {from}
 
format_status = {directory:>20} : {count:>5} Mails - {unseen:>5} Unseen - {recent:>5} Recent
 
limit = 10
 

	
 
[trash]
 
# delete method can be : MOVE_TO_TRASH, FLAG or EXPUNGE
 
delete_method = MOVE_TO_TRASH
 
trash_directory = Trash
roles/mail_server/tests/test_client2.py
Show inline comments
 
import re
 

	
 
import testinfra.utils.ansible_runner
 

	
 

	
 
testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(
 
    '.molecule/ansible_inventory').get_hosts('client2')
 

	
 
@@ -62,6 +65,15 @@ def test_mail_delivery(Command):
 
    assert send.rc == no_recipients_accepted
 
    assert "Recipient address rejected: User unknown in virtual mailbox table" in send.stdout
 

	
 
    # Test for valid mail address that's not allowed by LDAP group membership.
 
    send = Command('swaks --suppress-data --to nomail@domain1 --server parameters-mandatory')
 
    assert send.rc == no_recipients_accepted
 
    assert "Recipient address rejected: User unknown in virtual mailbox table" in send.stdout
 

	
 
    send = Command('swaks --suppress-data --to nomail@domain1 --server parameters-optional')
 
    assert send.rc == no_recipients_accepted
 
    assert "Recipient address rejected: User unknown in virtual mailbox table" in send.stdout
 

	
 
    # Valid aliases.
 
    send = Command('swaks --suppress-data --to postmaster@domain1 --server parameters-mandatory')
 
    assert send.rc == 0
 
@@ -103,6 +115,10 @@ def test_smtp_authentication(Command):
 
    anywhere.
 
    """
 

	
 
    send = Command('swaks -tls --port 587 --auth-user john.doe@domain1 --auth-password johnpassword --to root@client1 --server parameters-mandatory')
 
    assert send.rc == 0
 
    assert "Ok: queued as" in send.stdout
 

	
 
    send = Command('swaks -tls --port 587 --auth-user john.doe@domain1 --auth-password johnpassword --to root@client1 --server parameters-optional')
 
    assert send.rc == 0
 
    assert "Ok: queued as" in send.stdout
 
@@ -115,9 +131,13 @@ def test_smtp_authentication_requires_tls(Command):
 

	
 
    auth_error = 28
 

	
 
    send = Command('swaks --port 587 --auth-user john.doe@domain1 --auth-password johnpassword --to root@client1 --server parameters-mandatory')
 
    assert send.rc == auth_error
 
    assert "Host did not advertise authentication" in send.stderr
 

	
 
    send = Command('swaks --port 587 --auth-user john.doe@domain1 --auth-password johnpassword --to root@client1 --server parameters-optional')
 
    assert send.rc == auth_error
 
    assert "Host did not advertise authentication" in send.stdout
 
    assert "Host did not advertise authentication" in send.stderr
 

	
 

	
 
def test_smtp_authentication_requires_submission_port(Command):
 
@@ -127,10 +147,139 @@ def test_smtp_authentication_requires_submission_port(Command):
 

	
 
    auth_error = 28
 

	
 
    send = Command('swaks --port 25 --auth-user john.doe@domain1 --auth-password johnpassword --to root@client1 --server parameters-mandatory')
 
    assert send.rc == auth_error
 
    assert "Host did not advertise authentication" in send.stderr
 

	
 
    send = Command('swaks -tls --port 25 --auth-user john.doe@domain1 --auth-password johnpassword --to root@client1 --server parameters-mandatory')
 
    assert send.rc == auth_error
 
    assert "Host did not advertise authentication" in send.stderr
 

	
 
    send = Command('swaks --port 25 --auth-user john.doe@domain1 --auth-password johnpassword --to root@client1 --server parameters-optional')
 
    assert send.rc == auth_error
 
    assert "Host did not advertise authentication" in send.stdout
 
    assert "Host did not advertise authentication" in send.stderr
 

	
 
    send = Command('swaks -tls --port 25 --auth-user john.doe@domain1 --auth-password johnpassword --to root@client1 --server parameters-optional')
 
    assert send.rc == auth_error
 
    assert "Host did not advertise authentication" in send.stdout
 
    assert "Host did not advertise authentication" in send.stderr
 

	
 

	
 
def test_dovecot_inbox_separator(Command):
 
    """
 
    Tests if inbox separator has been configured correctly.
 
    """
 

	
 
    pattern_slash_separator = re.compile('WARNING:imap-cli:Ignoring "LIST" response part : \([^)]*\) "/" INBOX')
 
    pattern_dot_separator = re.compile('WARNING:imap-cli:Ignoring "LIST" response part : \([^)]*\) "\." INBOX')
 

	
 
    status = Command("imapcli status -c ~/imapcli-parameters-mandatory-john_doe.conf")
 
    assert pattern_slash_separator.search(status.stdout) is not None
 

	
 
    status = Command("imapcli status -c ~/imapcli-parameters-optional-john_doe.conf")
 
    assert pattern_dot_separator.search(status.stdout) is not None
 

	
 

	
 
def test_imap_authentication_requires_tls(Command):
 
    """
 
    Tests if IMAP authentication requires TLS.
 
    """
 

	
 
    # No TLS.
 
    command = Command("echo -e 'a0001 CAPABILITY\na0002 LOGOUT' | nc parameters-mandatory 143")
 
    assert command.rc == 0
 
    assert "LOGINDISABLED" in command.stdout
 

	
 
    command = Command("echo -e 'a0001 CAPABILITY\na0002 LOGOUT' | nc parameters-optional 143")
 
    assert command.rc == 0
 
    assert "LOGINDISABLED" in command.stdout
 

	
 
    # STARTTLS.
 
    command = Command("echo -e 'a0001 CAPABILITY\na0002 LOGOUT' | openssl s_client -quiet -connect parameters-mandatory:143 -starttls imap")
 
    assert command.rc == 0
 
    assert "LOGINDISABLED" not in command.stdout
 

	
 
    command = Command("echo -e 'a0001 CAPABILITY\na0002 LOGOUT' | openssl s_client -quiet -connect parameters-optional:143 -starttls imap")
 
    assert command.rc == 0
 
    assert "LOGINDISABLED" not in command.stdout
 

	
 
    # TLS.
 
    command = Command("echo -e 'a0001 CAPABILITY\na0002 LOGOUT' | openssl s_client -quiet -connect parameters-mandatory:993")
 
    assert command.rc == 0
 
    assert "LOGINDISABLED" not in command.stdout
 

	
 
    command = Command("echo -e 'a0001 CAPABILITY\na0002 LOGOUT' | openssl s_client -quiet -connect parameters-optional:993")
 
    assert command.rc == 0
 
    assert "LOGINDISABLED" not in command.stdout
 

	
 

	
 
def test_sieve_authentication_requires_tls(Command):
 
    """
 
    Tests if SIEVE authentication requires TLS.
 
    """
 

	
 
    # No TLS.
 
    command = Command("echo 'LOGOUT' | nc parameters-mandatory 4190")
 
    assert command.rc == 0
 
    assert "PLAIN LOGIN" not in command.stdout
 

	
 
    command = Command("echo 'LOGOUT' | nc parameters-optional 4190")
 
    assert command.rc == 0
 
    assert "PLAIN LOGIN" not in command.stdout
 

	
 
    # STARTTLS
 
    command = Command("echo 'johnpassword' | sieve-connect -u john.doe@domain1 --password 0 --server parameters-mandatory --port 4190 --list")
 
    assert command.rc == 0
 

	
 
    command = Command("echo 'johnpassword' | sieve-connect -u john.doe@domain1 --password 0 --server parameters-optional --port 4190 --list")
 
    assert command.rc == 0
 

	
 

	
 
def test_connectivity(Command, Sudo):
 
    """
 
    Tests connectivity to the mail server (ports that should be reachable).
 
    """
 

	
 
    with Sudo():
 

	
 
        for server in ["parameters-mandatory",
 
                       "parameters-optional"]:
 
            for port in [25, 26, 587, 143, 993, 4190]:
 

	
 
                ping = Command('hping3 -S -p %d -c 1 %s' % (port, server))
 
                assert ping.rc == 0
 

	
 

	
 
def test_port_forwarding(Command, Sudo):
 
    """
 
    Tests if port forwarding is set-up correctly for submission port.
 
    """
 

	
 
    send = Command('swaks -tls --port 26 --auth-user john.doe@domain1 --auth-password johnpassword --to root@client1 --server parameters-mandatory')
 
    assert send.rc == 0
 
    assert "Ok: queued as" in send.stdout
 

	
 
    send = Command('swaks -tls --port 26 --auth-user john.doe@domain1 --auth-password johnpassword --to root@client1 --server parameters-optional')
 
    assert send.rc == 0
 
    assert "Ok: queued as" in send.stdout
 

	
 

	
 
def test_dovecot_sieve(Command):
 
    """
 
    Tests if Sieve service is available.
 
    """
 

	
 
    # Test valid users.
 
    command = Command('echo johnpassword | sieve-connect --list -s parameters-mandatory -p 4190 -u john.doe@domain1 --password 0')
 
    assert command.rc == 0
 

	
 
    command = Command('echo janepassword | sieve-connect --list -s parameters-optional -p 4190 -u jane.doe@domain2 --password 0')
 
    assert command.rc == 0
 

	
 
    # Test invalid users.
 
    command = Command('echo johnpassword | sieve-connect --list -s parameters-mandatory -p 4190 -u john.doe@domain2 --password 0')
 
    assert command.rc != 0
 
    assert "Authentication refused by server" in command.stderr
 

	
 
    command = Command('echo janepassword | sieve-connect --list -s parameters-optional -p 4190 -u jane.doe@domain1 --password 0')
 
    assert command.rc != 0
 
    assert "Authentication refused by server" in command.stderr
roles/mail_server/tests/test_default.py
Show inline comments
 
@@ -189,6 +189,11 @@ def test_postfix_ldap_configuration(Command, Sudo):
 
        assert command.rc == 1
 
        assert command.stdout == ''
 

	
 
        # Test for valid mail address that's not allowed by LDAP group membership.
 
        command = Command("postmap -q 'nomail@domain1' ldap:/etc/postfix/ldap-virtual-mailbox-maps.cf")
 
        assert command.rc == 1
 
        assert command.stdout == ''
 

	
 
        # Test for valid mail aliases.
 
        command = Command("postmap -q postmaster@domain1 ldap:/etc/postfix/ldap-virtual-alias-maps.cf")
 
        assert command.rc == 0
 
@@ -234,3 +239,113 @@ def test_postfix_delivery_to_dovecot(Command, File, Sudo):
 
        mail_log = File('/var/log/mail.log')
 
        pattern = "dovecot: lda\(john.doe@domain1\): msgid=<[^.]*.%s@[^>]*>: saved mail to INBOX" % message_id
 
        assert re.search(pattern, mail_log.content) is not None
 

	
 

	
 
def test_dovecot_system_authentication_is_disabled(File):
 
    """
 
    Tests if Dovecot system-based authentication has been disabled.
 
    """
 

	
 
    config = File("/etc/dovecot/conf.d/10-auth.conf")
 

	
 
    assert "!include auth-system.conf.ext" not in config.content
 

	
 

	
 
def test_dovecot_overrides_configuration_file(File):
 
    """
 
    Tests if Dovecot configuration file with overrides has been deployed and has
 
    correct permissions.
 
    """
 

	
 
    config = File("/etc/dovecot/conf.d/99-local.conf")
 

	
 
    assert config.is_file
 
    assert config.user == 'root'
 
    assert config.group == 'root'
 
    assert config.mode == 0o644
 

	
 

	
 
def test_dovecot_imap_ldap_configuration(Command, Sudo):
 
    """
 
    Tests if Dovecot LDAP configuration is correct.
 
    """
 

	
 
    with Sudo():
 

	
 
        user_does_not_exist = 67
 

	
 
        # Test for valid mail addresses.
 
        command = Command("doveadm user john.doe@domain1")
 
        assert command.rc == 0
 

	
 
        command = Command("doveadm user jane.doe@domain2")
 
        assert command.rc == 0
 

	
 
        # Test for invalid mail addresses.
 
        command = Command("doveadm user john.doe@domain2")
 
        assert command.rc == user_does_not_exist
 

	
 
        command = Command("doveadm user jane.doe@domain1")
 
        assert command.rc == user_does_not_exist
 

	
 
        # Test for mail addresses present in LDAP, but entry not in mail group.
 
        command = Command("doveadm user nomail@domain1")
 
        assert command.rc == user_does_not_exist
 

	
 

	
 
def test_postfix_master_file(File):
 
    """
 
    Tests permissions for Postfix master.cf configuration file.
 
    """
 

	
 
    config = File('/etc/postfix/master.cf')
 

	
 
    assert config.is_file
 
    assert config.user == 'root'
 
    assert config.group == 'root'
 
    assert config.mode == 0o644
 

	
 

	
 
def test_services(Service):
 
    """
 
    Tests if all the mail-related servieces are up and running.
 
    """
 

	
 
    for service_name in ["clamav-daemon",
 
                         "clamav-freshclam",
 
                         "clamav-milter",
 
                         "postfix",
 
                         "dovecot"]:
 

	
 
        service = Service(service_name)
 
        assert service.is_running
 
        assert service.is_enabled
 

	
 

	
 
def test_clamav_database_presence(File):
 
    """
 
    Tests if ClamAV database is present.
 
    """
 

	
 
    for database_file in ["/var/lib/clamav/bytecode.cvd",
 
                          "/var/lib/clamav/daily.cld",
 
                          "/var/lib/clamav/main.cvd"]:
 

	
 
        database = File(database_file)
 

	
 
        assert database.is_file
 

	
 

	
 
def test_firewall_configuration_file(File, Sudo):
 
    """
 
    Tests if firewall configuration file has been deployed correctly.
 
    """
 

	
 
    with Sudo():
 

	
 
        config = File('/etc/ferm/conf.d/20-mail.conf')
 

	
 
        assert config.is_file
 
        assert config.user == 'root'
 
        assert config.group == 'root'
 
        assert config.mode == 0o640
roles/mail_server/tests/test_mandatory.py
Show inline comments
 
@@ -85,3 +85,165 @@ def test_postfix_main_cf_file_content(File):
 
    assert "smtpd_tls_cert_file = /etc/ssl/certs/parameters-mandatory_smtp.pem" in config_lines
 
    assert "smtpd_tls_key_file = /etc/ssl/private/parameters-mandatory_smtp.key" in config_lines
 
    assert "reject_rbl" not in config_lines
 

	
 

	
 
def test_dovecot_mailbox_directories(File, Sudo):
 
    """
 
    Tests if mailbox directories are created correctly.
 
    """
 

	
 
    with Sudo():
 

	
 
        for directory_path in ["/var/vmail/domain1",
 
                               "/var/vmail/domain1/john.doe",
 
                               "/var/vmail/domain1/john.doe/Maildir",
 
                               "/var/vmail/domain2",
 
                               "/var/vmail/domain2/jane.doe",
 
                               "/var/vmail/domain1/john.doe/Maildir"]:
 

	
 
            directory = File(directory_path)
 

	
 
            assert directory.is_directory
 
            assert directory.user == "vmail"
 
            assert directory.group == "vmail"
 
            assert directory.mode == 0o700
 

	
 

	
 
def test_mail_owner(Group, User):
 
    """
 
    Tests creation of mail owner group and user.
 
    """
 

	
 
    group = Group("vmail")
 
    assert group.exists
 
    assert group.gid == 1002
 

	
 
    user = User("vmail")
 
    assert user.exists
 
    assert user.uid == 1002
 
    assert user.home == "/var/vmail"
 
    assert user.group == "vmail"
 
    assert user.groups == ["vmail"]
 

	
 

	
 
def test_imap_tls_configuration(Command):
 
    """
 
    Tests TLS configuration for IMAP in Dovecot.
 
    """
 

	
 
    # Test plain connectivity first.
 
    starttls = Command('echo "a0001 LOGOUT" | openssl s_client -quiet -starttls imap -connect parameters-mandatory:143')
 
    assert starttls.rc == 0
 
    assert '* BYE Logging out' in starttls.stdout
 

	
 
    tls = Command('echo "a0001 LOGOUT" | openssl s_client -quiet -connect parameters-mandatory:993')
 
    assert tls.rc == 0
 
    assert '* BYE Logging out' in starttls.stdout
 

	
 
    # Test TLS protocol versions.
 
    starttls_old_tls_versions_disabled = Command("echo 'a0001 LOGOUT' | openssl s_client -quiet -starttls imap -no_tls1_2 -connect parameters-mandatory:143")
 
    assert starttls_old_tls_versions_disabled.rc != 0
 
    assert "write:errno=104" in starttls_old_tls_versions_disabled.stderr
 

	
 
    tls_old_tls_versions_disabled = Command("echo 'a0001 LOGOUT' | openssl s_client -quiet -no_tls1_2 -connect parameters-mandatory:993")
 
    assert tls_old_tls_versions_disabled.rc != 0
 
    assert "write:errno=104" in tls_old_tls_versions_disabled.stderr
 

	
 
    # Test at least one strong TLS cipher.
 
    starttls_cipher = Command("echo 'a0001 LOGOUT' | openssl s_client -starttls imap -cipher ECDHE-RSA-AES128-SHA256 -connect parameters-mandatory:143")
 
    assert starttls_cipher.rc == 0
 
    assert "ECDHE-RSA-AES128-SHA256" in starttls_cipher.stdout
 

	
 
    tls_cipher = Command("echo 'a0001 LOGOUT' | openssl s_client -cipher ECDHE-RSA-AES128-SHA256 -connect parameters-mandatory:993")
 
    assert tls_cipher.rc == 0
 
    assert "ECDHE-RSA-AES128-SHA256" in tls_cipher.stdout
 

	
 
    # Test weaker TLS cipher are disabled.
 
    starttls_cipher = Command("echo 'a0001 LOGOUT' | openssl s_client -starttls imap -cipher ECDHE-RSA-AES128-SHA -connect parameters-mandatory:143")
 
    assert starttls_cipher.rc != 0
 
    assert "ECDHE-RSA-AES128-SHA" not in starttls_cipher.stdout
 

	
 
    tls_cipher = Command("echo 'a0001 LOGOUT' | openssl s_client -cipher ECDHE-RSA-AES128-SHA -connect parameters-mandatory:993")
 
    assert tls_cipher.rc != 0
 
    assert "ECDHE-RSA-AES128-SHA" not in tls_cipher.stdout
 

	
 

	
 
def test_dovecot_postmaster(Command, Sudo):
 
    """
 
    Tests if Dovecot postmaster has been correctly configured.
 
    """
 

	
 
    with Sudo():
 

	
 
        config = Command("doveadm config")
 
        assert config.rc == 0
 
        assert "  postmaster_address = postmaster@" in config.stdout
 

	
 

	
 
def test_imap_max_user_connections_per_ip(Command, Sudo):
 
    """
 
    Tests if Dovecot per-user connection limit has been set-up correctly.
 
    """
 

	
 
    with Sudo():
 

	
 
        config = Command("doveadm config")
 

	
 
        assert config.rc == 0
 
        assert "  mail_max_userip_connections = 10" in config.stdout
 

	
 

	
 
def test_postfix_tls_configuration(Command):
 
    """
 
    Tests TLS configuration for SMTP in Postfix.
 
    """
 

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

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

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

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

	
 
    starttls = Command("echo 'QUIT' | openssl s_client -quiet -starttls smtp -no_tls1_2 -connect parameters-mandatory:587")
 
    assert starttls.rc != 0
 
    assert 'write:errno=104' in starttls.stderr
 

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

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

	
 
    # Test ciphers for submission port (weak ciphers not available).
 
    starttls_cipher = Command("echo 'QUIT' | openssl s_client -starttls smtp -cipher ECDHE-RSA-AES128-SHA256 -connect parameters-mandatory:587")
 
    assert starttls_cipher.rc == 0
 
    assert "ECDHE-RSA-AES128-SHA256" in starttls_cipher.stdout
 

	
 
    starttls_cipher = Command("echo 'QUIT' | openssl s_client -starttls smtp -cipher ECDHE-RSA-AES128-SHA -connect parameters-mandatory:587")
 
    assert starttls_cipher.rc != 0
 
    assert "ECDHE-RSA-AES128-SHA" not in starttls_cipher.stdout
 

	
 

	
 
def test_sieve_tls_configuration(Command):
 
    """
 
    Tests TLS configuration for SIEVE in Dovecot
 
    """
 

	
 
    # @TODO: Currently not possible to test since openssl s_client does not
 
    # support STARTTLS for Sieve.
 
    pass
roles/mail_server/tests/test_optional.py
Show inline comments
 
@@ -104,3 +104,178 @@ def test_local_aliases(Command, File, Sudo):
 
        mail_log = File('/var/log/mail.log')
 
        pattern = "dovecot: lda\(john.doe@domain1\): msgid=<[^.]*.%s@[^>]*>: saved mail to INBOX" % message_id
 
        assert re.search(pattern, mail_log.content) is not None
 

	
 

	
 
def test_dovecot_mailbox_directories(File, Sudo):
 
    """
 
    Tests if mailbox directories are created correctly.
 
    """
 

	
 
    with Sudo():
 

	
 
        for directory_path in ["/var/virtmail/domain1",
 
                               "/var/virtmail/domain1/john.doe",
 
                               "/var/virtmail/domain1/john.doe/Maildir",
 
                               "/var/virtmail/domain2",
 
                               "/var/virtmail/domain2/jane.doe",
 
                               "/var/virtmail/domain1/john.doe/Maildir"]:
 

	
 
            directory = File(directory_path)
 

	
 
            assert directory.is_directory
 
            assert directory.user == "virtmail"
 
            assert directory.group == "virtmail"
 
            assert directory.mode == 0o700
 

	
 

	
 
def test_mail_owner(Group, User):
 
    """
 
    Tests creation of mail owner group and user.
 
    """
 

	
 
    group = Group("virtmail")
 
    assert group.exists
 
    assert group.gid == 5000
 

	
 
    user = User("virtmail")
 
    assert user.exists
 
    assert user.uid == 5000
 
    assert user.home == "/var/virtmail"
 
    assert user.group == "virtmail"
 
    assert user.groups == ["virtmail"]
 

	
 

	
 
def test_imap_tls_configuration(Command):
 
    """
 
    Tests TLS configuration for IMAP in Dovecot.
 
    """
 

	
 
    # Test plain connectivity first.
 
    starttls = Command('echo "a0001 LOGOUT" | openssl s_client -quiet -starttls imap -connect parameters-optional:143')
 
    assert starttls.rc == 0
 
    assert '* BYE Logging out' in starttls.stdout
 

	
 
    tls = Command('echo "a0001 LOGOUT" | openssl s_client -quiet -connect parameters-optional:993')
 
    assert tls.rc == 0
 
    assert '* BYE Logging out' in starttls.stdout
 

	
 
    # Test TLS protocol versions.
 
    starttls = Command('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 = Command('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
 

	
 
    starttls = Command("echo 'a0001 LOGOUT' | openssl s_client -quiet -starttls imap -no_tls1_1 -no_tls1_2 -connect parameters-optional:143")
 
    assert starttls.rc != 0
 
    assert "write:errno=104" in starttls.stderr
 

	
 
    tls = Command("echo 'a0001 LOGOUT' | openssl s_client -quiet -no_tls1_1 -no_tls1_2 -connect parameters-optional:993")
 
    assert tls.rc != 0
 
    assert "write:errno=104" in tls.stderr
 

	
 
    # Test at least one strong TLS cipher.
 
    starttls_cipher = Command("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_cipher = Command("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
 

	
 
    # Test weaker TLS cipher that was explicitly configured
 
    starttls_cipher = Command("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
 

	
 
    tls_cipher = Command("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
 

	
 

	
 
def test_dovecot_postmaster(Command, Sudo):
 
    """
 
    Tests if Dovecot postmaster has been correctly configured.
 
    """
 

	
 
    with Sudo():
 

	
 
        config = Command("doveadm config")
 

	
 
        assert config.rc == 0
 
        assert "  postmaster_address = webmaster@parameters-optional" in config.stdout
 

	
 

	
 
def test_imap_max_user_connections_per_ip(Command, Sudo):
 
    """
 
    Tests if Dovecot per-user connection limit has been set-up correctly.
 
    """
 

	
 
    with Sudo():
 

	
 
        config = Command("doveadm config")
 

	
 
        assert config.rc == 0
 
        assert "  mail_max_userip_connections = 2" in config.stdout
 

	
 

	
 
def test_postfix_tls_configuration(Command):
 
    """
 
    Tests TLS configuration for SMTP in Postfix.
 
    """
 

	
 
    # Test TLS protocol versions for default port (all should be enabled).
 
    starttls = Command("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 = Command("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 = Command("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 = Command("echo 'QUIT' | openssl s_client -quiet -starttls smtp -connect parameters-optional:587")
 
    assert starttls.rc == 0
 
    assert '221 2.0.0 Bye' in starttls.stdout
 

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

	
 
    starttls = Command("echo 'QUIT' | openssl s_client -quiet -starttls smtp -no_tls1_1 -no_tls1_2 -connect parameters-optional:587")
 
    assert starttls.rc != 0
 
    assert 'write:errno=104' in starttls.stderr
 

	
 
    # Test ciphers for default port (less restrictive).
 
    starttls_cipher = Command("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 = Command("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 = Command("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
 

	
 
    starttls_cipher = Command("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
 

	
 

	
 
def test_sieve_tls_configuration(Command):
 
    """
 
    Tests TLS configuration for SIEVE in Dovecot
 
    """
 

	
 
    # @TODO: Currently not possible to test since openssl s_client does not
 
    # support STARTTLS for Sieve.
 
    pass
0 comments (0 inline, 0 general)