refactor test to be more strict

This commit is contained in:
holger krekel
2023-10-18 14:41:49 +02:00
parent c6d8f7e759
commit 6701c9749c
2 changed files with 84 additions and 31 deletions

View File

@@ -75,6 +75,15 @@ class ImapConn:
print(f"imap-login {user!r} {password!r}") print(f"imap-login {user!r} {password!r}")
self.conn.login(user, password) 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 @pytest.fixture
def smtp(maildomain): def smtp(maildomain):
@@ -97,6 +106,11 @@ class SmtpConn:
print(f"smtp-login {user!r} {password!r}") print(f"smtp-login {user!r} {password!r}")
self.conn.login(user, password) 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"]) @pytest.fixture(params=["imap", "smtp"])
def imap_or_smtp(request): def imap_or_smtp(request):
@@ -198,7 +212,11 @@ class Remote:
) )
while 1: while 1:
line = self.popen.stdout.readline() line = self.popen.stdout.readline()
yield line.decode().strip().lower() res = line.decode().strip().lower()
if res:
yield res
else:
break
@pytest.fixture @pytest.fixture
@@ -209,3 +227,51 @@ def mailgen(request):
return data.format(from_addr=from_addr, to_addr=to_addr) return data.format(from_addr=from_addr, to_addr=to_addr)
return Mailgen() 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

View File

@@ -19,42 +19,29 @@ def test_use_two_chatmailservers(cmfactory, maildomain2):
assert domain1 != domain2 assert domain1 != domain2
def test_reject_internal_forged_from(smtp, gencreds, mailgen, lp, imap): def test_reject_internal_forged_from(cmsetup, mailgen, lp, remote):
lp.sec("create forged user account") user1, user2, user3 = cmsetup.gen_users(3)
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)
lp.sec("send encrypted message with forged from") lp.sec("send encrypted message with forged from")
print("envelope_from", login_user) print("envelope_from", user1.addr)
print("logged in as", login_user) print("message to inject:")
msg = mailgen.get_encrypted(from_addr=user2.addr, to_addr=user3.addr)
print("injected mime message")
msg = mailgen.get_encrypted(from_addr=forged_user, to_addr=to_user)
for line in msg.split("\n")[:4]: for line in msg.split("\n")[:4]:
print(f" {line}") 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() for line in remote_log:
imap.login(login_user, login_password) print(line)
imap.conn.select("Inbox") if "500 invalid from" in line:
break
else:
pytest.fail("remote postfix/filtermail failed to reject message")
# detect mailer daemon rejection message # also check that the forging-user got a non-delivery notice
status, results = imap.conn.fetch("1", "(RFC822)") for flags, bmsg in user1.imap.fetch_all():
assert status == "OK" message = bmsg.decode()
for res in results: if "Invalid FROM" in message and user2.addr in message:
message = res[1].decode()
if "Invalid FROM" in message and forged_user in message:
return return
pytest.fail("forged From did not cause rejection") pytest.fail("forged From did not cause rejection")