Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor ssl tooling using trustme #807

Merged
merged 9 commits into from
Oct 12, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pytest
pytest-mock
requests
mypy
trustme
coverage

# Documentation
Expand Down
92 changes: 27 additions & 65 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,72 +1,34 @@
import pytest
import trustme

CERTIFICATE = b"""-----BEGIN CERTIFICATE-----
MIIEaDCCAtCgAwIBAgIRAPeU748qfVOTZJ7rj5DupbowDQYJKoZIhvcNAQELBQAw
fTEeMBwGA1UEChMVbWtjZXJ0IGRldmVsb3BtZW50IENBMSkwJwYDVQQLDCBmcmFp
cjUwMEBmcmFpcjUwMC1QcmVjaXNpb24tNTUyMDEwMC4GA1UEAwwnbWtjZXJ0IGZy
YWlyNTAwQGZyYWlyNTAwLVByZWNpc2lvbi01NTIwMB4XDTE5MDEwOTIwMzQ1N1oX
DTI5MDEwOTIwMzQ1N1owVDEnMCUGA1UEChMebWtjZXJ0IGRldmVsb3BtZW50IGNl
cnRpZmljYXRlMSkwJwYDVQQLDCBmcmFpcjUwMEBmcmFpcjUwMC1QcmVjaXNpb24t
NTUyMDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALahGo80UFExe7Iv
jPDulPP9Vu3mPVW/4XhrvmbwjHPSXk6nvK34kdDmGsS/UVgtSMH+sdMNFavkhyK/
b6PW5dPy+febfxlnaOkrZ5ptYx5IG1l/CNY/QDpQKGljW9YGQDV2t9apgKgT1/Ob
JIKf/rfd2o94iyxlrRnbXXidyMa1E6loo1AzzaN/g17dnblIL7ZCZtflgbsgnytw
UtwS92kTsvMHvuzM7Paz2M0xx+RNtQ2rq51fwph55gn7HLlBFEbkrMsfFj7hEquC
vJYvyrIEvaQLMyIOf+6/OgmrG9Z5ioMV4WAW9FLSuzXuuJruQc7FwQl4XIuE8d0M
jPjRfIcCAwEAAaOBizCBiDAOBgNVHQ8BAf8EBAMCBaAwEwYDVR0lBAwwCgYIKwYB
BQUHAwEwDAYDVR0TAQH/BAIwADAfBgNVHSMEGDAWgBTfMtd0Al3Ly09elEje6jyl
b3EQmjAyBgNVHREEKzApgglsb2NhbGhvc3SHBAAAAACHBH8AAAGHEAAAAAAAAAAA
AAAAAAAAAAEwDQYJKoZIhvcNAQELBQADggGBADLu7RSMVnUiRNyTqIM3aMmkUXmL
xSPB/SZRifqVwmp9R6ygAZWzC7Lw5BpX2WCde1jqWJZw1AjYbe4w5i8e9jaiUyYZ
eaLuQN7/+dyWeMIfFKx7thDxmati+OkSJSoojROA1v4NY7QAIM6ycfFkwTBRokPz
42srfR+XXrvdNmBRqjpvpr48SAn44uvqAkVr3kNgqs1xycPgjsFvMO7qZlU6w/ev
/7QFUgtyZS/Saa4s3yRXHZ++g3SpPinrzf8VqmovL/MoaqB/tYVjOA/1B3QAkli6
DIl+99eKANlqARXzMeXvgLpcg+1oAw0hYjFpCtqKhovhQzqN6KlAbmJ9JWTk35x8
81nOERZH5dh6JZoHzaaB/ZMEjWkmHnyi4bf5dXiPLzfXJslbQKHhnSt4nfZiSodS
brUVv/sux119zyUPe9iA6NNPFS/No1XOKcHrG19jiXTq/HIdJRoIrN6eRJDTRVK1
HyJ6uTvTJDu4ceBp2J1gz7R5opWbGyytDGg3Tw==
-----END CERTIFICATE-----
"""

PRIVATE_KEY = b"""-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC2oRqPNFBRMXuy
L4zw7pTz/Vbt5j1Vv+F4a75m8Ixz0l5Op7yt+JHQ5hrEv1FYLUjB/rHTDRWr5Ici
v2+j1uXT8vn3m38ZZ2jpK2eabWMeSBtZfwjWP0A6UChpY1vWBkA1drfWqYCoE9fz
mySCn/633dqPeIssZa0Z2114ncjGtROpaKNQM82jf4Ne3Z25SC+2QmbX5YG7IJ8r
cFLcEvdpE7LzB77szOz2s9jNMcfkTbUNq6udX8KYeeYJ+xy5QRRG5KzLHxY+4RKr
gryWL8qyBL2kCzMiDn/uvzoJqxvWeYqDFeFgFvRS0rs17ria7kHOxcEJeFyLhPHd
DIz40XyHAgMBAAECggEAZ1q7Liob/icz6r5wU/WhhIduB8qSEZI65qyLH7Sot+9p
Abh51jbjRsbChXAEeBOAppEeT+OKzTHSrH6MjrtSa+WJQ3DTuCvGupae1k1rl7qV
B8wV0zIOhjHQ/PuHAJOfCOK73ZclwXkhcLLvMaGcRLAgPaupj6GnGggEWPtqodDo
qBOcixT3/lMW5M1GklkqJqbD8g8qcx7SFBwORJjpwVX84Ynnursu0ZvTfK/CzZTk
D5t/UXyRV5Y5QBkzKIKzC0qUHv4eMIqkzlPBYx2PnAgrHokOm9/RS28yKT2DVPhw
t311ZM6+Z5AxfKamARWZbZdC8RG5Qo0ujLmgogNn2QKBgQDsqpwO+/yJlvF81nf9
0Ye5o0OdOdD5q1ra46PyhQ56hIC5cRZx3s3E9hUFDcot81qj9nMTpSGJL5J6GqAY
W7p3PbpYxT27MDjthgHHcZy7hu1M9no65ZAK1ElxVhKMgl89RQu/HQoa6Uh3qjbF
X0edTBTBJoGOYQ1lVaoL8s307QKBgQDFjGtEKubolZ0OqFb361fDcYs0RDKNlNxy
RIMM6Dhl0tgGHxNFuFNlLdjKyPEltfNaK0L0W3i3Ndf5sUlr2MuXYgO6RRqWo/D2
Tr2/jd6gsVKLK871WD7IS5SbCirCwuEsZQsZ2J2TWECoPqc8L3iZwyW6VGRkIW+K
o2Sl7P4cwwKBgQCnhAt6P7p82S6NInFEY28iYwGU5DuavUNN9BszqiKZbfh/SiCM
8RvM8jHmpeAZrkrWC7dgjF20cMvJSddP5n2RsUuZUeNj/7oLxfK0bSJ3SgXlmADk
d2EBiUmCw13VvuISyDCMUc25Rq5YpU6nXc2e9R8rqEnDscZ9l6kJVA+b8QKBgBAZ
coB6spjP4J3aMERCJMPj1AFtcWVCdXjGhpudrUL3HO3ayHpNHFbJlrpoB+cX3f5C
OlGpxru/optRzHcCkw0CSuV6TkFqmO+p2SLsT/Fuohh/eH1cNLmkFzdPa861jR5O
GcqAcc8ZSSOs/3oTMFPvqHp3+DqE0w9MY552Ivt7AoGATtJkMAg9M4U/5qIsCbRz
LplSCRvcarrg+czXW1re6y117rVjRHPCHgT//azsBDER0WpWSGv7XEnZwnz8U6Cn
FCXoiqqEJuD2wLwQlhb7QVXYTMdCwfPj5WV7ARJO1N4ty3g8x+jnTQCVoMpdhgxC
Sflxx+6bI4XMh0AsZhgtdW4=
-----END PRIVATE KEY-----
"""
@pytest.fixture
def tls_certificate_authority() -> trustme.CA:
return trustme.CA()


@pytest.fixture(scope="function")
def certfile_and_keyfile(tmp_path):
certfile = str(tmp_path / "cert.pem")
with open(certfile, "bw") as fout:
fout.write(CERTIFICATE)
@pytest.fixture
def tls_certificate(tls_certificate_authority):
return tls_certificate_authority.issue_server_cert(
"localhost",
"127.0.0.1",
"::1",
)

keyfile = str(tmp_path / "key.pem")
with open(keyfile, "bw") as fout:
fout.write(PRIVATE_KEY)

return certfile, keyfile
@pytest.fixture
def tls_ca_certificate_pem_path(tls_certificate_authority):
with tls_certificate_authority.cert_pem.tempfile() as ca_cert_pem:
yield ca_cert_pem


@pytest.fixture
def tls_ca_certificate_private_key_path(tls_certificate_authority):
with tls_certificate_authority.private_key_pem.tempfile() as private_key:
yield private_key


@pytest.fixture
def tls_certificate_pem_path(tls_certificate):
with tls_certificate.private_key_and_cert_chain_pem.tempfile() as cert_pem:
yield cert_pem
4 changes: 3 additions & 1 deletion tests/supervisors/test_watchgodreload.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ def run(sockets):
pass


def test_watchgodreload(certfile_and_keyfile):
def test_watchgodreload(
tls_ca_certificate_pem_path, tls_ca_certificate_private_key_path
):
config = Config(app=None)
reloader = WatchGodReload(config, target=run, sockets=[])
reloader.signal_handler(sig=signal.SIGINT, frame=None)
Expand Down
19 changes: 16 additions & 3 deletions tests/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,22 @@ def test_socket_bind():
assert isinstance(config.bind_socket(), socket.socket)


def test_ssl_config(certfile_and_keyfile):
certfile, keyfile = certfile_and_keyfile
config = Config(app=asgi_app, ssl_certfile=certfile, ssl_keyfile=keyfile)
def test_ssl_config(tls_ca_certificate_pem_path, tls_ca_certificate_private_key_path):
config = Config(
app=asgi_app,
ssl_certfile=tls_ca_certificate_pem_path,
ssl_keyfile=tls_ca_certificate_private_key_path,
)
config.load()

assert config.is_ssl is True


def test_ssl_config_combined(tls_certificate_pem_path):
config = Config(
app=asgi_app,
ssl_certfile=tls_certificate_pem_path,
)
config.load()

assert config.is_ssl is True
Expand Down
40 changes: 36 additions & 4 deletions tests/test_ssl.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,42 @@ def no_ssl_verification(session=requests.Session):
@pytest.mark.skipif(
sys.platform.startswith("win"), reason="Skipping SSL test on Windows"
)
def test_run(certfile_and_keyfile):
certfile, keyfile = certfile_and_keyfile
def test_run(tls_ca_certificate_pem_path, tls_ca_certificate_private_key_path):
class App:
def __init__(self, scope):
if scope["type"] != "http":
raise Exception()

async def __call__(self, receive, send):
await send({"type": "http.response.start", "status": 204, "headers": []})
await send({"type": "http.response.body", "body": b"", "more_body": False})

class CustomServer(Server):
def install_signal_handlers(self):
pass

config = Config(
app=App,
loop="asyncio",
limit_max_requests=1,
ssl_keyfile=tls_ca_certificate_private_key_path,
ssl_certfile=tls_ca_certificate_pem_path,
)
server = CustomServer(config=config)
thread = threading.Thread(target=server.run)
thread.start()
while not server.started:
time.sleep(0.01)
with no_ssl_verification():
response = requests.get("https://127.0.0.1:8000")
assert response.status_code == 204
thread.join()


@pytest.mark.skipif(
sys.platform.startswith("win"), reason="Skipping SSL test on Windows"
)
def test_run_chain(tls_certificate_pem_path):
class App:
def __init__(self, scope):
if scope["type"] != "http":
Expand All @@ -48,8 +81,7 @@ def install_signal_handlers(self):
app=App,
loop="asyncio",
limit_max_requests=1,
ssl_keyfile=keyfile,
ssl_certfile=certfile,
ssl_certfile=tls_certificate_pem_path,
)
server = CustomServer(config=config)
thread = threading.Thread(target=server.run)
Expand Down