From 6701c9749ca7393eced8423957c67bd472da519f Mon Sep 17 00:00:00 2001 From: holger krekel Date: Wed, 18 Oct 2023 14:41:49 +0200 Subject: [PATCH] refactor test to be more strict --- online-tests/conftest.py | 68 +++++++++++++++++++++++++++++++++++- online-tests/test_0_basic.py | 47 +++++++++---------------- 2 files changed, 84 insertions(+), 31 deletions(-) diff --git a/online-tests/conftest.py b/online-tests/conftest.py index 4be5057f..7ec39bf0 100644 --- a/online-tests/conftest.py +++ b/online-tests/conftest.py @@ -75,6 +75,15 @@ class ImapConn: print(f"imap-login {user!r} {password!r}") self.conn.login(user, password) + def fetch_all(self): + print("imap-fetch all") + status, res = self.conn.select() + if int(res[0]) == 0: + raise ValueError("no messages in imap folder") + status, results = self.conn.fetch("1:*", "(RFC822)") + assert status == "OK" + return results + @pytest.fixture def smtp(maildomain): @@ -97,6 +106,11 @@ class SmtpConn: print(f"smtp-login {user!r} {password!r}") self.conn.login(user, password) + def sendmail(self, from_addr, to_addrs, msg): + print(f"smtp-sendmail from={from_addr!r} to_addrs={to_addrs!r}") + print(f"smtp-sendmail message size: {len(msg)}") + return self.conn.sendmail(from_addr=from_addr, to_addrs=to_addrs, msg=msg) + @pytest.fixture(params=["imap", "smtp"]) def imap_or_smtp(request): @@ -198,7 +212,11 @@ class Remote: ) while 1: line = self.popen.stdout.readline() - yield line.decode().strip().lower() + res = line.decode().strip().lower() + if res: + yield res + else: + break @pytest.fixture @@ -209,3 +227,51 @@ def mailgen(request): return data.format(from_addr=from_addr, to_addr=to_addr) return Mailgen() + + +@pytest.fixture +def cmsetup(maildomain, gencreds): + return CMSetup(maildomain, gencreds) + + +class CMSetup: + def __init__(self, maildomain, gencreds): + self.maildomain = maildomain + self.gencreds = gencreds + + def gen_users(self, num): + print(f"Creating {num} online users") + users = [] + for i in range(num): + addr, password = self.gencreds() + user = CMUser(self.maildomain, addr, password) + assert user.smtp + users.append(user) + return users + + +class CMUser: + def __init__(self, maildomain, addr, password): + self.maildomain = maildomain + self.addr = addr + self.password = password + self._smtp = None + self._imap = None + + @property + def smtp(self): + if not self._smtp: + handle = SmtpConn(self.maildomain) + handle.connect() + handle.login(self.addr, self.password) + self._smtp = handle + return self._smtp + + @property + def imap(self): + if not self._imap: + imap = ImapConn(self.maildomain) + imap.connect() + imap.login(self.addr, self.password) + self._imap = imap + return self._imap diff --git a/online-tests/test_0_basic.py b/online-tests/test_0_basic.py index 4244762b..c3c475cb 100644 --- a/online-tests/test_0_basic.py +++ b/online-tests/test_0_basic.py @@ -19,42 +19,29 @@ def test_use_two_chatmailservers(cmfactory, maildomain2): assert domain1 != domain2 -def test_reject_internal_forged_from(smtp, gencreds, mailgen, lp, imap): - lp.sec("create forged user account") - forged_user, password = gencreds() - smtp.connect() - smtp.login(forged_user, password) - - lp.sec("create TO user account") - to_user, password = gencreds() - smtp.connect() - smtp.login(to_user, password) - - lp.sec("create account") - login_user, login_password = gencreds() - smtp.connect() - smtp.login(login_user, login_password) +def test_reject_internal_forged_from(cmsetup, mailgen, lp, remote): + user1, user2, user3 = cmsetup.gen_users(3) lp.sec("send encrypted message with forged from") - print("envelope_from", login_user) - print("logged in as", login_user) - - print("injected mime message") - msg = mailgen.get_encrypted(from_addr=forged_user, to_addr=to_user) + print("envelope_from", user1.addr) + print("message to inject:") + msg = mailgen.get_encrypted(from_addr=user2.addr, to_addr=user3.addr) for line in msg.split("\n")[:4]: print(f" {line}") - smtp.conn.sendmail(from_addr=login_user, to_addrs=[to_user], msg=msg) + remote_log = remote.iter_output("journalctl -t postfix/lmtp") + user1.smtp.sendmail(from_addr=user1.addr, to_addrs=[user3.addr], msg=msg) - imap.connect() - imap.login(login_user, login_password) - imap.conn.select("Inbox") + for line in remote_log: + print(line) + if "500 invalid from" in line: + break + else: + pytest.fail("remote postfix/filtermail failed to reject message") - # detect mailer daemon rejection message - status, results = imap.conn.fetch("1", "(RFC822)") - assert status == "OK" - for res in results: - message = res[1].decode() - if "Invalid FROM" in message and forged_user in message: + # also check that the forging-user got a non-delivery notice + for flags, bmsg in user1.imap.fetch_all(): + message = bmsg.decode() + if "Invalid FROM" in message and user2.addr in message: return pytest.fail("forged From did not cause rejection")