summaryrefslogtreecommitdiff
path: root/src/mailman/testing
diff options
context:
space:
mode:
authorJ08nY2017-03-13 02:14:26 +0100
committerJ08nY2017-07-24 18:44:19 +0200
commitad463598885ecc91bee9fbca5aea9fcb4e9f627e (patch)
tree9363afa79afaf75c32742c57b6e1cee8754d7a32 /src/mailman/testing
parent02826321d0430d7ffc1f674eeff4221941689ef7 (diff)
downloadmailman-mta-smtps-starttls.tar.gz
mailman-mta-smtps-starttls.tar.zst
mailman-mta-smtps-starttls.zip
Diffstat (limited to 'src/mailman/testing')
-rw-r--r--src/mailman/testing/layers.py118
-rw-r--r--src/mailman/testing/mta.py53
-rw-r--r--src/mailman/testing/ssl_test_cert.crt21
-rw-r--r--src/mailman/testing/ssl_test_key.key28
4 files changed, 213 insertions, 7 deletions
diff --git a/src/mailman/testing/layers.py b/src/mailman/testing/layers.py
index dbed1fccf..54ba4f5a1 100644
--- a/src/mailman/testing/layers.py
+++ b/src/mailman/testing/layers.py
@@ -25,6 +25,7 @@
# get rid of the layers and use something like testresources or some such.
import os
+import ssl
import sys
import shutil
import logging
@@ -40,14 +41,15 @@ from mailman.database.transaction import transaction
from mailman.interfaces.domain import IDomainManager
from mailman.testing.helpers import (
TestableMaster, get_lmtp_client, reset_the_world, wait_for_webservice)
-from mailman.testing.mta import ConnectionCountingController
+from mailman.testing.mta import (
+ ConnectionCountingController, ConnectionCountingSSLController,
+ ConnectionCountingSTARTLSController)
from mailman.utilities.string import expand
-from pkg_resources import resource_string as resource_bytes
+from pkg_resources import resource_filename, resource_string as resource_bytes
from public import public
from textwrap import dedent
from zope.component import getUtility
-
TEST_TIMEOUT = datetime.timedelta(seconds=5)
NL = '\n'
@@ -259,6 +261,116 @@ class SMTPLayer(ConfigLayer):
@public
+class SMTPSLayer(ConfigLayer):
+ """Layer for starting, stopping, and accessing a test SMTPS server."""
+
+ smtpd = None
+
+ @classmethod
+ def setUp(cls):
+ assert cls.smtpd is None, 'Layer already set up'
+ # Use a different port than the SMTP layer, since that one might
+ # still be in use.
+ config.push('smtps', """
+ [mta]
+ smtp_port: 9026
+ smtp_protocol: smtps
+ """)
+ test_cert_path = resource_filename('mailman.testing',
+ 'ssl_test_cert.crt')
+ test_key_path = resource_filename('mailman.testing',
+ 'ssl_test_key.key')
+
+ client_context = ssl.create_default_context()
+ client_context.load_verify_locations(cafile=test_cert_path)
+
+ server_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
+ server_context.load_cert_chain(test_cert_path, test_key_path)
+
+ host = config.mta.smtp_host
+ port = int(config.mta.smtp_port)
+
+ cls.smtpd = ConnectionCountingSSLController(
+ host, port,
+ client_context=client_context,
+ server_context=server_context)
+ cls.smtpd.start()
+
+ @classmethod
+ def testSetUp(cls):
+ # Make sure we don't call our superclass's testSetUp(), otherwise the
+ # example.com domain will get added twice.
+ pass
+
+ @classmethod
+ def testTearDown(cls):
+ cls.smtpd.reset()
+ cls.smtpd.clear()
+
+ @classmethod
+ def tearDown(cls):
+ assert cls.smtpd is not None, 'Layer not set up'
+ cls.smtpd.clear()
+ cls.smtpd.stop()
+ config.pop('smtps')
+
+
+@public
+class STARTTLSLayer(ConfigLayer):
+ """Layer for starting and stopping a test SMTP server with STARTTLS."""
+
+ smtpd = None
+
+ @classmethod
+ def setUp(cls):
+ assert cls.smtpd is None, 'Layer already set up'
+ # Use a different port than the SMTP and SMTPS layers, since that one
+ # might still be in use.
+ config.push('starttls', """
+ [mta]
+ smtp_port: 9027
+ smtp_protocol: starttls
+ """)
+ test_cert_path = resource_filename('mailman.testing',
+ 'ssl_test_cert.crt')
+ test_key_path = resource_filename('mailman.testing',
+ 'ssl_test_key.key')
+
+ client_context = ssl.create_default_context()
+ client_context.load_verify_locations(cafile=test_cert_path)
+
+ server_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
+ server_context.load_cert_chain(test_cert_path, test_key_path)
+
+ host = config.mta.smtp_host
+ port = int(config.mta.smtp_port)
+
+ cls.smtpd = ConnectionCountingSTARTLSController(
+ host, port,
+ client_context=client_context,
+ server_context=server_context)
+ cls.smtpd.start()
+
+ @classmethod
+ def testSetUp(cls):
+ # Make sure we don't call our superclass's testSetUp(), otherwise the
+ # example.com domain will get added twice.
+ pass
+
+ @classmethod
+ def testTearDown(cls):
+ cls.smtpd.reset()
+ cls.smtpd.clear()
+
+ @classmethod
+ def tearDown(cls):
+ assert cls.smtpd is not None, 'Layer not set up'
+ cls.smtpd.clear()
+ cls.smtpd.stop()
+ config.pop('starttls')
+
+
+@public
class LMTPLayer(ConfigLayer):
"""Layer for starting, stopping, and accessing a test LMTP server."""
diff --git a/src/mailman/testing/mta.py b/src/mailman/testing/mta.py
index ef4d39233..02a3b83d2 100644
--- a/src/mailman/testing/mta.py
+++ b/src/mailman/testing/mta.py
@@ -166,12 +166,14 @@ class ConnectionCountingSMTP(SMTP):
class ConnectionCountingController(Controller):
"""Count the number of SMTP connections opened."""
- def __init__(self, host, port):
+ def __init__(self, host, port, ssl_context=None):
self._msg_queue = Queue()
self._oob_queue = Queue()
self.err_queue = Queue()
+
handler = ConnectionCountingHandler(self._msg_queue)
- super().__init__(handler, hostname=host, port=port)
+ super().__init__(handler, hostname=host, port=port,
+ ssl_context=ssl_context)
def factory(self):
return ConnectionCountingSMTP(
@@ -184,8 +186,7 @@ class ConnectionCountingController(Controller):
self.reset()
def _connect(self):
- client = smtplib.SMTP()
- client.connect(self.hostname, self.port)
+ client = smtplib.SMTP(self.hostname, self.port)
return client
def get_connection_count(self):
@@ -223,3 +224,47 @@ class ConnectionCountingController(Controller):
def reset(self):
client = self._connect()
client.docmd('RSET')
+
+
+class ConnectionCountingSSLController(ConnectionCountingController):
+ """Count the number of SMTPS connections opened."""
+
+ def __init__(self, host, port, client_context=None, server_context=None):
+ super().__init__(host, port, ssl_context=server_context)
+ self._client_context = client_context
+
+ def _connect(self):
+ client = smtplib.SMTP_SSL(self.hostname, self.port,
+ context=self._client_context)
+ return client
+
+
+class ConnectionCountingSTARTLSController(ConnectionCountingController):
+ """Count the number of SMTP connections with STARTTLS opened."""
+
+ def __init__(self, host, port, client_context=None, server_context=None):
+ super().__init__(host, port)
+ self._client_context = client_context
+ self._server_context = server_context
+
+ def factory(self):
+ return ConnectionCountingSMTP(
+ self.handler, self._oob_queue,
+ self.err_queue, tls_context=self._server_context,
+ require_starttls=True)
+
+ def _connect(self):
+ client = smtplib.SMTP(self.hostname, self.port)
+ client.starttls(context=self._client_context)
+ return client
+
+ def get_connection_count(self):
+ count = super().get_connection_count()
+ # This is a hack, since when using STARTTLS for every connection the
+ # SMTP.connection_made(transport) method is called twice.
+ # The -1 is there for the last pair of connections made when checking
+ # the connection count, since one of them is already subtracted in
+ # ConnectionCountingSMTP.handle_STAT.
+ # The //2 is there for the rest of the connections which are counted
+ # twice.
+ return (count - 1) // 2
diff --git a/src/mailman/testing/ssl_test_cert.crt b/src/mailman/testing/ssl_test_cert.crt
new file mode 100644
index 000000000..06ae8ac9d
--- /dev/null
+++ b/src/mailman/testing/ssl_test_cert.crt
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDeDCCAmCgAwIBAgIJANA3MRKsRL/OMA0GCSqGSIb3DQEBCwUAMFExCzAJBgNV
+BAYTAlVTMQswCQYDVQQIDAJNQTEhMB8GA1UECgwYTWFpbG1hbiB0ZXN0IGNlcnRp
+ZmljYXRlMRIwEAYDVQQDDAlsb2NhbGhvc3QwHhcNMTcwNTI3MTYxNzIzWhcNMjcw
+NTI1MTYxNzIzWjBRMQswCQYDVQQGEwJVUzELMAkGA1UECAwCTUExITAfBgNVBAoM
+GE1haWxtYW4gdGVzdCBjZXJ0aWZpY2F0ZTESMBAGA1UEAwwJbG9jYWxob3N0MIIB
+IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAycCl/y9Cpm0jW921eIraIieh
+cxXPrYed66SxZwoZNt8StaFfNOeqykIiFpUR/5KYc1Sk0yF2tGfFv6l17xG0fuCI
+OkH1EynhXZiPbdcvmqF2W6Fa1g5kZJ//KbhK4rRsUEVp/2pHVjMG6toenM+S/1LE
+35XiNyIHF6ZeENAb/zR3ikjYH0MSEq2doBmKd9/m48+z5Vb+MbyIG7jbvN3MQ9f/
+NXAIwcGf37RO5+yNIcvqTV9SMBAZb1l+rMrsks6Ghr3NoBP1kuqJF5vFropKBx7R
+1MKvYm2ISL5UaWbFPYs9A4VhtzhMWBLZGHQPFHnR7dub7et8eiC7fbsdx4uyGwID
+AQABo1MwUTAdBgNVHQ4EFgQUe1Q+FbXTQjLoeTuSlxQQCeE+jpQwHwYDVR0jBBgw
+FoAUe1Q+FbXTQjLoeTuSlxQQCeE+jpQwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG
+9w0BAQsFAAOCAQEANbliLrarZfinHQ+/TQIOdqolsscw7RtyFtB7wA2uqWNsH/77
+EYDiv8AhpAQB3dzKwGdapgYgsWUe2awSD67TAJg5XS/h9F1PbbjDYGC9v6T7HDPd
+SfGV34LbWmH60rE6B1lwyCACnOXhByFGrdicCm2Z073kTp5L7WuAqpwC1f3aMC0u
+9goUWHSfqSIPPIv8yiV0vgKk4kP4KV/gi20x74c31pujExCiVGA4GGTXV9hqmAm7
+tZuPTYFN5n60U1tzbFXOuwK6CvCDzWeq27mYwNHTXSJw1GyG4XXM5t2wfSlu/4e4
+xDuZwvP0P7hTME5wC7KGeS7daYSWNCDiHa7g6A==
+-----END CERTIFICATE-----
diff --git a/src/mailman/testing/ssl_test_key.key b/src/mailman/testing/ssl_test_key.key
new file mode 100644
index 000000000..619556893
--- /dev/null
+++ b/src/mailman/testing/ssl_test_key.key
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDJwKX/L0KmbSNb
+3bV4itoiJ6FzFc+th53rpLFnChk23xK1oV8056rKQiIWlRH/kphzVKTTIXa0Z8W/
+qXXvEbR+4Ig6QfUTKeFdmI9t1y+aoXZboVrWDmRkn/8puEritGxQRWn/akdWMwbq
+2h6cz5L/UsTfleI3IgcXpl4Q0Bv/NHeKSNgfQxISrZ2gGYp33+bjz7PlVv4xvIgb
+uNu83cxD1/81cAjBwZ/ftE7n7I0hy+pNX1IwEBlvWX6syuySzoaGvc2gE/WS6okX
+m8WuikoHHtHUwq9ibYhIvlRpZsU9iz0DhWG3OExYEtkYdA8UedHt25vt63x6ILt9
+ux3Hi7IbAgMBAAECggEATRjFVmLlAVwrauuqcUn+WZbzZ1sqZZGxk174O/vr7sAI
+Ekh8bWcqKOhkxmRo4FVQ1KG/6r6a8g3Fz5weaSFG7EU5Sany0UPrzyyBguP8WQbi
+h9l9MNeHHbzWcUbvtvpjeblM7EHcyN/vAMghcqMP9WnXuek47QCf3TXCNIKScE8a
+sU01o7Lw4CkZOLP9UyLmoKiQpurj7jWOMq10QOG4693dnfcgz7voPZPrt8OnAo7x
+ap4ojK9nWfjFHFxpsddBhXBxzXw/U8FxtzYtCbzxL7iYpxpq0GEc/5eF8O+RE4MX
+D1uqrkLfVM4HMOgQoFLrSGcPahYSVRrQ3X+lYV+OQQKBgQDotmodstq4T3D+7buY
+J3zi+saEDvcPxgy31934jm465WfNiYSrnq5PqJCkzVpYMPuj0O8za75OoyRK2viT
+glBKjP0vxNXh91tTi4eU7LCFPNwOwnt+e3tu+eA4klFpQIEUI8PHlEe4VBGlvpsD
+DoPHuIHCouAEXhpu/ck58+QxKQKBgQDd8Rshc7h8PY26Rxrzgjob9PvDHxQODodU
+iRUAELscSkr4gwYTgmDL4vL+lOog7IAYGmSOsHLJ19wTbLsaPMPfhUh+zXuvwlA5
+/01uYFp0UM4ax4DdTGPA5qOAIkLY3rL1x6U0eBf6XJhdG8mTW9SjbD1aCbDGdZk6
+9KJVUlDdowKBgD4NHeCLZ1zL+gJP27ynktpnKfXek6xGD/AZhFuZhvT3ZKVerNyi
+NDKTbPY0t4lajk7REGcyrI0FXVEEcFHM5qHqVDyfjLRzI4v0YZOpRSxR3Q+mdg10
+2aXuxQXwpfqds41uN+8Ir9MLv6TlXSoEfckMfrUqfvdLLFs6GqT0Tn15AoGBANG0
+05HUKekasCPms8yKrCVmYcyIPQbbK3vw2uro5CNi/1u5UbB1bMi5dCigxGi/jnk3
+1vQMPSoC0Gt6PYAZEmrNISbPOaNk0zE5zgwQ9ucYwuYCw/xWBZtrUensdYU9R5N8
+RNlC8EUb4Mt5Sgn2pwCTcZT1uxaKX3KZXBmKYeZJAoGAAtWlzPxgwDglNhhuLpgW
+vSOH0lpHlR//Ne7kMPCfG4lrAaPo5VSfQrjlzoF9tlhu0IuRKnwOg4HmFD9COaLA
+RWTNDLMxBct5lZNAjgIzI5nZm6VLioCQkAdThzSBTxpGrIR0iDR99RWf/M4p7cK6
+tiqX285r1nogUpROl0uraV4=
+-----END PRIVATE KEY-----