From d6c38a0bab062b0a5f2597e12b83b8e175be0b2a Mon Sep 17 00:00:00 2001 From: Povilas Kanapickas Date: Sat, 4 May 2024 23:52:57 +0300 Subject: [PATCH] tests: Add tests for how Let's Encrypt ACME challenge is handled At the moment no changes to functionality are done, only the current behavior is captured. --- test/conftest.py | 7 ++++++ .../.well-known/acme-challenge/test-filename | 1 + test/test_ssl/test_https_port.py | 9 ++++++++ test/test_ssl/test_https_port.yml | 1 + test/test_ssl/test_nohttp.py | 7 ++++++ test/test_ssl/test_nohttp.yml | 1 + test/test_ssl/test_nohttps.py | 8 +++++++ test/test_ssl/test_nohttps.yml | 1 + test/test_ssl/test_noredirect.py | 10 +++++++- test/test_ssl/test_noredirect.yml | 1 + test/test_ssl/test_virtual_path.py | 9 ++++++++ test/test_ssl/test_virtual_path.yml | 1 + test/test_ssl/test_wildcard.py | 10 ++++++++ test/test_ssl/test_wildcard.yml | 1 + .../.well-known/acme-challenge/test-filename | 1 + .../docker-compose.yml | 1 + .../test_wildcard_cert_nohttps.py | 23 +++++++++++++++++++ 17 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 test/test_ssl/acme_root/.well-known/acme-challenge/test-filename create mode 100644 test/test_ssl/wildcard_cert_and_nohttps/acme_root/.well-known/acme-challenge/test-filename diff --git a/test/conftest.py b/test/conftest.py index 7fa269a..dda20f6 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -510,6 +510,13 @@ def nginxproxy(): yield requests_for_docker() +@pytest.fixture() +def acme_challenge_path(): + """ + Provides fake Let's Encrypt ACME challenge path used in certain tests + """ + return ".well-known/acme-challenge/test-filename" + ############################################################################### # # Py.test hooks diff --git a/test/test_ssl/acme_root/.well-known/acme-challenge/test-filename b/test/test_ssl/acme_root/.well-known/acme-challenge/test-filename new file mode 100644 index 0000000..5b45dff --- /dev/null +++ b/test/test_ssl/acme_root/.well-known/acme-challenge/test-filename @@ -0,0 +1 @@ +challenge-teststring diff --git a/test/test_ssl/test_https_port.py b/test/test_ssl/test_https_port.py index 27a42ef..ebe305f 100644 --- a/test/test_ssl/test_https_port.py +++ b/test/test_ssl/test_https_port.py @@ -17,3 +17,12 @@ def test_nonstandardport_Host_header(docker_compose, nginxproxy): r = nginxproxy.get("https://web.nginx-proxy.tld:8443/headers") assert r.status_code == 200 assert "Host: web.nginx-proxy.tld:8443" in r.text + +@pytest.mark.parametrize("subdomain", ["foo", "bar"]) +def test_web1_acme_challenge_works(docker_compose, nginxproxy, acme_challenge_path, subdomain): + r = nginxproxy.get( + f"http://{subdomain}.nginx-proxy.tld:8080/{acme_challenge_path}", + allow_redirects=False + ) + assert r.status_code == 200 + assert "challenge-teststring\n" in r.text diff --git a/test/test_ssl/test_https_port.yml b/test/test_ssl/test_https_port.yml index 047054a..b6541ac 100644 --- a/test/test_ssl/test_https_port.yml +++ b/test/test_ssl/test_https_port.yml @@ -14,6 +14,7 @@ services: volumes: - /var/run/docker.sock:/tmp/docker.sock:ro - ./certs:/etc/nginx/certs:ro + - ./acme_root:/usr/share/nginx/html:ro environment: HTTP_PORT: 8080 HTTPS_PORT: 8443 diff --git a/test/test_ssl/test_nohttp.py b/test/test_ssl/test_nohttp.py index 5b650db..aecbb54 100644 --- a/test/test_ssl/test_nohttp.py +++ b/test/test_ssl/test_nohttp.py @@ -7,6 +7,13 @@ def test_web2_http_is_connection_refused(docker_compose, nginxproxy): nginxproxy.get("http://web2.nginx-proxy.tld/") +def test_web2_http_is_connection_refused_for_acme_challenge( + docker_compose, nginxproxy, acme_challenge_path +): + with pytest.raises(requests.exceptions.RequestException, match="Connection refused"): + nginxproxy.get(f"http://web2.nginx-proxy.tld/{acme_challenge_path}") + + def test_web2_https_is_forwarded(docker_compose, nginxproxy): r = nginxproxy.get("https://web2.nginx-proxy.tld/port", allow_redirects=False) assert r.status_code == 200 diff --git a/test/test_ssl/test_nohttp.yml b/test/test_ssl/test_nohttp.yml index 40b393a..0c21bf9 100644 --- a/test/test_ssl/test_nohttp.yml +++ b/test/test_ssl/test_nohttp.yml @@ -15,3 +15,4 @@ services: volumes: - /var/run/docker.sock:/tmp/docker.sock:ro - ./certs:/etc/nginx/certs:ro + - ./acme_root:/usr/share/nginx/html:ro diff --git a/test/test_ssl/test_nohttps.py b/test/test_ssl/test_nohttps.py index 1cedf82..23e8224 100644 --- a/test/test_ssl/test_nohttps.py +++ b/test/test_ssl/test_nohttps.py @@ -10,3 +10,11 @@ def test_http_is_forwarded(docker_compose, nginxproxy): def test_https_is_disabled(docker_compose, nginxproxy): with pytest.raises(ConnectionError): nginxproxy.get("https://web.nginx-proxy.tld/", allow_redirects=False) + + +def test_http_acme_challenge_does_not_work(docker_compose, nginxproxy, acme_challenge_path): + r = nginxproxy.get( + f"http://web.nginx-proxy.tld/{acme_challenge_path}", + allow_redirects=False + ) + assert r.status_code == 404 diff --git a/test/test_ssl/test_nohttps.yml b/test/test_ssl/test_nohttps.yml index f2b0757..209f57a 100644 --- a/test/test_ssl/test_nohttps.yml +++ b/test/test_ssl/test_nohttps.yml @@ -14,3 +14,4 @@ services: image: nginxproxy/nginx-proxy:test volumes: - /var/run/docker.sock:/tmp/docker.sock:ro + - ./acme_root:/usr/share/nginx/html:ro diff --git a/test/test_ssl/test_noredirect.py b/test/test_ssl/test_noredirect.py index 62df28b..0f50063 100644 --- a/test/test_ssl/test_noredirect.py +++ b/test/test_ssl/test_noredirect.py @@ -16,4 +16,12 @@ def test_web3_https_is_forwarded(docker_compose, nginxproxy): def test_web2_HSTS_policy_is_inactive(docker_compose, nginxproxy): r = nginxproxy.get("https://web3.nginx-proxy.tld/port", allow_redirects=False) assert "answer from port 83\n" in r.text - assert "Strict-Transport-Security" not in r.headers \ No newline at end of file + assert "Strict-Transport-Security" not in r.headers + + +def test_web3_acme_challenge_does_not_work(docker_compose, nginxproxy, acme_challenge_path): + r = nginxproxy.get( + f"http://web3.nginx-proxy.tld/{acme_challenge_path}", + allow_redirects=False + ) + assert r.status_code == 404 diff --git a/test/test_ssl/test_noredirect.yml b/test/test_ssl/test_noredirect.yml index 8ee8455..7610ae2 100644 --- a/test/test_ssl/test_noredirect.yml +++ b/test/test_ssl/test_noredirect.yml @@ -15,3 +15,4 @@ services: volumes: - /var/run/docker.sock:/tmp/docker.sock:ro - ./certs:/etc/nginx/certs:ro + - ./acme_root:/usr/share/nginx/html:ro diff --git a/test/test_ssl/test_virtual_path.py b/test/test_ssl/test_virtual_path.py index 508653f..72ac433 100644 --- a/test/test_ssl/test_virtual_path.py +++ b/test/test_ssl/test_virtual_path.py @@ -1,4 +1,5 @@ import pytest +from requests import ConnectionError @pytest.mark.parametrize("path", ["web1", "web2"]) def test_web1_http_redirects_to_https(docker_compose, nginxproxy, path): @@ -13,3 +14,11 @@ def test_web1_https_is_forwarded(docker_compose, nginxproxy, path, port): assert r.status_code == 200 assert "answer from port %d\n" % port in r.text + +@pytest.mark.parametrize("port", [81, 82]) +def test_acme_challenge_does_not_work(docker_compose, nginxproxy, acme_challenge_path, port): + with pytest.raises(ConnectionError): + nginxproxy.get( + f"http://www.nginx-proxy.tld:{port}/{acme_challenge_path}", + allow_redirects=False + ) diff --git a/test/test_ssl/test_virtual_path.yml b/test/test_ssl/test_virtual_path.yml index 2494d35..eb09ef0 100644 --- a/test/test_ssl/test_virtual_path.yml +++ b/test/test_ssl/test_virtual_path.yml @@ -26,3 +26,4 @@ services: volumes: - /var/run/docker.sock:/tmp/docker.sock:ro - ./certs:/etc/nginx/certs:ro + - ./acme_root:/usr/share/nginx/html:ro diff --git a/test/test_ssl/test_wildcard.py b/test/test_ssl/test_wildcard.py index 202ba24..f019f68 100644 --- a/test/test_ssl/test_wildcard.py +++ b/test/test_ssl/test_wildcard.py @@ -21,3 +21,13 @@ def test_web1_HSTS_policy_is_active(docker_compose, nginxproxy, subdomain): r = nginxproxy.get(f"https://{subdomain}.nginx-proxy.tld/port", allow_redirects=False) assert "answer from port 81\n" in r.text assert "Strict-Transport-Security" in r.headers + + +@pytest.mark.parametrize("subdomain", ["foo", "bar"]) +def test_web1_acme_challenge_works(docker_compose, nginxproxy, acme_challenge_path, subdomain): + r = nginxproxy.get( + f"http://web3.nginx-proxy.tld/{acme_challenge_path}", + allow_redirects=False + ) + assert r.status_code == 200 + assert "challenge-teststring\n" in r.text diff --git a/test/test_ssl/test_wildcard.yml b/test/test_ssl/test_wildcard.yml index ea8c596..b101e9f 100644 --- a/test/test_ssl/test_wildcard.yml +++ b/test/test_ssl/test_wildcard.yml @@ -14,3 +14,4 @@ services: volumes: - /var/run/docker.sock:/tmp/docker.sock:ro - ./certs:/etc/nginx/certs:ro + - ./acme_root:/usr/share/nginx/html:ro diff --git a/test/test_ssl/wildcard_cert_and_nohttps/acme_root/.well-known/acme-challenge/test-filename b/test/test_ssl/wildcard_cert_and_nohttps/acme_root/.well-known/acme-challenge/test-filename new file mode 100644 index 0000000..5b45dff --- /dev/null +++ b/test/test_ssl/wildcard_cert_and_nohttps/acme_root/.well-known/acme-challenge/test-filename @@ -0,0 +1 @@ +challenge-teststring diff --git a/test/test_ssl/wildcard_cert_and_nohttps/docker-compose.yml b/test/test_ssl/wildcard_cert_and_nohttps/docker-compose.yml index 98f41a0..7cc64e7 100644 --- a/test/test_ssl/wildcard_cert_and_nohttps/docker-compose.yml +++ b/test/test_ssl/wildcard_cert_and_nohttps/docker-compose.yml @@ -7,6 +7,7 @@ services: volumes: - /var/run/docker.sock:/tmp/docker.sock:ro - ./certs:/etc/nginx/certs:ro + - ./acme_root:/usr/share/nginx/html:ro web1: image: web diff --git a/test/test_ssl/wildcard_cert_and_nohttps/test_wildcard_cert_nohttps.py b/test/test_ssl/wildcard_cert_and_nohttps/test_wildcard_cert_nohttps.py index 4453779..d07437d 100644 --- a/test/test_ssl/wildcard_cert_and_nohttps/test_wildcard_cert_nohttps.py +++ b/test/test_ssl/wildcard_cert_and_nohttps/test_wildcard_cert_nohttps.py @@ -1,5 +1,6 @@ import pytest from ssl import CertificateError +from requests import ConnectionError from requests.exceptions import SSLError @@ -32,3 +33,25 @@ def test_https_request_to_nohttps_vhost_goes_to_fallback_server(docker_compose, r = nginxproxy.get("https://3.web.nginx-proxy.tld/port", verify=False) assert r.status_code == 503 + + +@pytest.mark.parametrize("subdomain,acme_should_work", [ + (1, True), + (2, True), + (3, False), +]) +def test_acme_challenge_works( + docker_compose, nginxproxy, acme_challenge_path, subdomain, acme_should_work +): + if acme_should_work: + r = nginxproxy.get( + f"https://{subdomain}.web.nginx-proxy.tld/{acme_challenge_path}", + allow_redirects=False + ) + assert r.status_code == 404 + else: + with pytest.raises(ConnectionError): + nginxproxy.get( + f"https://{subdomain}.web.nginx-proxy.tld/{acme_challenge_path}", + allow_redirects=False + )