mirror of
https://github.com/apache/httpd.git
synced 2025-07-25 17:01:22 +00:00
Arrange pytest to run with mod_ssl, still skipping some tests.
this closes #433 git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1917039 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
@ -39,7 +39,9 @@ def env(pytestconfig) -> MDTestEnv:
|
|||||||
@pytest.fixture(autouse=True, scope="package")
|
@pytest.fixture(autouse=True, scope="package")
|
||||||
def _md_package_scope(env):
|
def _md_package_scope(env):
|
||||||
env.httpd_error_log.add_ignored_lognos([
|
env.httpd_error_log.add_ignored_lognos([
|
||||||
"AH10085" # There are no SSL certificates configured and no other module contributed any
|
"AH10085", # There are no SSL certificates configured and no other module contributed any
|
||||||
|
"AH10045", # No VirtualHost matches Managed Domain
|
||||||
|
"AH10105", # MDomain does not match any VirtualHost with 'SSLEngine on'
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
|
@ -13,7 +13,10 @@ class TlsTestConf(HttpdConf):
|
|||||||
|
|
||||||
def start_tls_vhost(self, domains: List[str], port=None, ssl_module=None):
|
def start_tls_vhost(self, domains: List[str], port=None, ssl_module=None):
|
||||||
if ssl_module is None:
|
if ssl_module is None:
|
||||||
ssl_module = 'mod_tls'
|
if not self.env.has_shared_module("tls"):
|
||||||
|
ssl_module = "mod_ssl"
|
||||||
|
else:
|
||||||
|
ssl_module = 'mod_tls'
|
||||||
super().start_vhost(domains=domains, port=port, doc_root=f"htdocs/{domains[0]}", ssl_module=ssl_module)
|
super().start_vhost(domains=domains, port=port, doc_root=f"htdocs/{domains[0]}", ssl_module=ssl_module)
|
||||||
|
|
||||||
def end_tls_vhost(self):
|
def end_tls_vhost(self):
|
||||||
@ -39,8 +42,12 @@ class TlsTestConf(HttpdConf):
|
|||||||
f" MDCertificateKeyFile {pkey_file}",
|
f" MDCertificateKeyFile {pkey_file}",
|
||||||
])
|
])
|
||||||
self.add("</MDomain>")
|
self.add("</MDomain>")
|
||||||
|
if self.env.has_shared_module("tls"):
|
||||||
|
ssl_module= "mod_tls"
|
||||||
|
else:
|
||||||
|
ssl_module= "mod_ssl"
|
||||||
super().add_vhost(domains=[domain], port=port, doc_root=f"htdocs/{domain}",
|
super().add_vhost(domains=[domain], port=port, doc_root=f"htdocs/{domain}",
|
||||||
with_ssl=True, with_certificates=False, ssl_module='mod_tls')
|
with_ssl=True, with_certificates=False, ssl_module=ssl_module)
|
||||||
|
|
||||||
def add_md_base(self, domain: str):
|
def add_md_base(self, domain: str):
|
||||||
self.add([
|
self.add([
|
||||||
|
@ -129,7 +129,10 @@ class TlsTestEnv(HttpdTestEnv):
|
|||||||
]),
|
]),
|
||||||
CertificateSpec(name="user1", client=True, single_file=True),
|
CertificateSpec(name="user1", client=True, single_file=True),
|
||||||
])
|
])
|
||||||
self.add_httpd_log_modules(['tls'])
|
if not HttpdTestEnv.has_shared_module("tls"):
|
||||||
|
self.add_httpd_log_modules(['ssl'])
|
||||||
|
else:
|
||||||
|
self.add_httpd_log_modules(['tls'])
|
||||||
|
|
||||||
|
|
||||||
def setup_httpd(self, setup: TlsTestSetup = None):
|
def setup_httpd(self, setup: TlsTestSetup = None):
|
||||||
|
@ -64,9 +64,15 @@ class TestConf:
|
|||||||
])
|
])
|
||||||
def test_tls_02_conf_cert_listen_valid(self, env, listen: str):
|
def test_tls_02_conf_cert_listen_valid(self, env, listen: str):
|
||||||
conf = TlsTestConf(env=env)
|
conf = TlsTestConf(env=env)
|
||||||
conf.add("TLSEngine {listen}".format(listen=listen))
|
if not env.has_shared_module("tls"):
|
||||||
conf.install()
|
# Without cert/key openssl will complain
|
||||||
assert env.apache_restart() == 0
|
conf.add("SSLEngine on");
|
||||||
|
conf.install()
|
||||||
|
assert env.apache_restart() == 1
|
||||||
|
else:
|
||||||
|
conf.add("TLSEngine {listen}".format(listen=listen))
|
||||||
|
conf.install()
|
||||||
|
assert env.apache_restart() == 0
|
||||||
|
|
||||||
def test_tls_02_conf_cert_listen_cert(self, env):
|
def test_tls_02_conf_cert_listen_cert(self, env):
|
||||||
domain = env.domain_a
|
domain = env.domain_a
|
||||||
|
@ -181,7 +181,10 @@ class TestCiphers:
|
|||||||
})
|
})
|
||||||
conf.add_tls_vhosts(domains=[env.domain_a, env.domain_b])
|
conf.add_tls_vhosts(domains=[env.domain_a, env.domain_b])
|
||||||
conf.install()
|
conf.install()
|
||||||
assert env.apache_restart() == 0
|
if not conf.env.has_shared_module("tls"):
|
||||||
|
assert env.apache_restart() != 0
|
||||||
|
else:
|
||||||
|
assert env.apache_restart() == 0
|
||||||
#
|
#
|
||||||
env.httpd_error_log.ignore_recent(
|
env.httpd_error_log.ignore_recent(
|
||||||
lognos = [
|
lognos = [
|
||||||
@ -204,4 +207,6 @@ class TestCiphers:
|
|||||||
})
|
})
|
||||||
conf.add_tls_vhosts(domains=[env.domain_a, env.domain_b])
|
conf.add_tls_vhosts(domains=[env.domain_a, env.domain_b])
|
||||||
conf.install()
|
conf.install()
|
||||||
|
if not conf.env.has_shared_module("tls"):
|
||||||
|
return
|
||||||
assert env.apache_restart() == 0
|
assert env.apache_restart() == 0
|
||||||
|
@ -23,7 +23,10 @@ class TestVars:
|
|||||||
def test_tls_08_vars_root(self, env):
|
def test_tls_08_vars_root(self, env):
|
||||||
# in domain_b root, the StdEnvVars is switch on
|
# in domain_b root, the StdEnvVars is switch on
|
||||||
exp_proto = "TLSv1.2"
|
exp_proto = "TLSv1.2"
|
||||||
exp_cipher = "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"
|
if env.has_shared_module("tls"):
|
||||||
|
exp_cipher = "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"
|
||||||
|
else:
|
||||||
|
exp_cipher = "ECDHE-ECDSA-AES256-GCM-SHA384"
|
||||||
options = [ '--tls-max', '1.2']
|
options = [ '--tls-max', '1.2']
|
||||||
r = env.tls_get(env.domain_b, "/vars.py", options=options)
|
r = env.tls_get(env.domain_b, "/vars.py", options=options)
|
||||||
assert r.exit_code == 0, r.stderr
|
assert r.exit_code == 0, r.stderr
|
||||||
@ -47,7 +50,12 @@ class TestVars:
|
|||||||
def test_tls_08_vars_const(self, env, name: str, value: str):
|
def test_tls_08_vars_const(self, env, name: str, value: str):
|
||||||
r = env.tls_get(env.domain_b, f"/vars.py?name={name}")
|
r = env.tls_get(env.domain_b, f"/vars.py?name={name}")
|
||||||
assert r.exit_code == 0, r.stderr
|
assert r.exit_code == 0, r.stderr
|
||||||
assert r.json == {name: value}, r.stdout
|
if env.has_shared_module("tls"):
|
||||||
|
assert r.json == {name: value}, r.stdout
|
||||||
|
else:
|
||||||
|
if name == "SSL_SECURE_RENEG":
|
||||||
|
value = "true"
|
||||||
|
assert r.json == {name: value}, r.stdout
|
||||||
|
|
||||||
@pytest.mark.parametrize("name, pattern", [
|
@pytest.mark.parametrize("name, pattern", [
|
||||||
("SSL_VERSION_INTERFACE", r'mod_tls/\d+\.\d+\.\d+'),
|
("SSL_VERSION_INTERFACE", r'mod_tls/\d+\.\d+\.\d+'),
|
||||||
@ -57,4 +65,11 @@ class TestVars:
|
|||||||
r = env.tls_get(env.domain_b, f"/vars.py?name={name}")
|
r = env.tls_get(env.domain_b, f"/vars.py?name={name}")
|
||||||
assert r.exit_code == 0, r.stderr
|
assert r.exit_code == 0, r.stderr
|
||||||
assert name in r.json
|
assert name in r.json
|
||||||
assert re.match(pattern, r.json[name]), r.json
|
if env.has_shared_module("tls"):
|
||||||
|
assert re.match(pattern, r.json[name]), r.json
|
||||||
|
else:
|
||||||
|
if name == "SSL_VERSION_INTERFACE":
|
||||||
|
pattern = r'mod_ssl/\d+\.\d+\.\d+'
|
||||||
|
else:
|
||||||
|
pattern = r'OpenSSL/\d+\.\d+\.\d+'
|
||||||
|
assert re.match(pattern, r.json[name]), r.json
|
||||||
|
@ -2,6 +2,7 @@ import re
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from .conf import TlsTestConf
|
from .conf import TlsTestConf
|
||||||
|
from pyhttpd.env import HttpdTestEnv
|
||||||
|
|
||||||
|
|
||||||
class TestProxySSL:
|
class TestProxySSL:
|
||||||
@ -9,6 +10,12 @@ class TestProxySSL:
|
|||||||
@pytest.fixture(autouse=True, scope='class')
|
@pytest.fixture(autouse=True, scope='class')
|
||||||
def _class_scope(self, env):
|
def _class_scope(self, env):
|
||||||
# add vhosts a+b and a ssl proxy from a to b
|
# add vhosts a+b and a ssl proxy from a to b
|
||||||
|
if not HttpdTestEnv.has_shared_module("tls"):
|
||||||
|
myoptions="SSLOptions +StdEnvVars"
|
||||||
|
myssl="mod_ssl"
|
||||||
|
else:
|
||||||
|
myoptions="TLSOptions +StdEnvVars"
|
||||||
|
myssl="mod_tls"
|
||||||
conf = TlsTestConf(env=env, extras={
|
conf = TlsTestConf(env=env, extras={
|
||||||
'base': [
|
'base': [
|
||||||
"LogLevel proxy:trace1 proxy_http:trace1 ssl:trace1 proxy_http2:trace1",
|
"LogLevel proxy:trace1 proxy_http:trace1 ssl:trace1 proxy_http2:trace1",
|
||||||
@ -33,10 +40,10 @@ class TestProxySSL:
|
|||||||
f'ProxyPass /proxy-ssl/ https://127.0.0.1:{env.https_port}/',
|
f'ProxyPass /proxy-ssl/ https://127.0.0.1:{env.https_port}/',
|
||||||
f'ProxyPass /proxy-local/ https://localhost:{env.https_port}/',
|
f'ProxyPass /proxy-local/ https://localhost:{env.https_port}/',
|
||||||
f'ProxyPass /proxy-h2-ssl/ h2://127.0.0.1:{env.https_port}/',
|
f'ProxyPass /proxy-h2-ssl/ h2://127.0.0.1:{env.https_port}/',
|
||||||
"TLSOptions +StdEnvVars",
|
myoptions,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
conf.add_tls_vhosts(domains=[env.domain_a, env.domain_b])
|
conf.add_tls_vhosts(domains=[env.domain_a, env.domain_b], ssl_module=myssl)
|
||||||
conf.install()
|
conf.install()
|
||||||
assert env.apache_restart() == 0
|
assert env.apache_restart() == 0
|
||||||
|
|
||||||
@ -69,7 +76,24 @@ class TestProxySSL:
|
|||||||
("SSL_CIPHER_EXPORT", "false"),
|
("SSL_CIPHER_EXPORT", "false"),
|
||||||
("SSL_CLIENT_VERIFY", "NONE"),
|
("SSL_CLIENT_VERIFY", "NONE"),
|
||||||
])
|
])
|
||||||
|
def test_tls_14_proxy_tsl_vars_const(self, env, name: str, value: str):
|
||||||
|
if not HttpdTestEnv.has_shared_module("tls"):
|
||||||
|
return
|
||||||
|
r = env.tls_get(env.domain_b, f"/proxy-ssl/vars.py?name={name}")
|
||||||
|
assert r.exit_code == 0, r.stderr
|
||||||
|
assert r.json == {name: value}, r.stdout
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("name, value", [
|
||||||
|
("SERVER_NAME", "b.mod-tls.test"),
|
||||||
|
("SSL_SESSION_RESUMED", "Initial"),
|
||||||
|
("SSL_SECURE_RENEG", "true"),
|
||||||
|
("SSL_COMPRESS_METHOD", "NULL"),
|
||||||
|
("SSL_CIPHER_EXPORT", "false"),
|
||||||
|
("SSL_CLIENT_VERIFY", "NONE"),
|
||||||
|
])
|
||||||
def test_tls_14_proxy_ssl_vars_const(self, env, name: str, value: str):
|
def test_tls_14_proxy_ssl_vars_const(self, env, name: str, value: str):
|
||||||
|
if HttpdTestEnv.has_shared_module("tls"):
|
||||||
|
return
|
||||||
r = env.tls_get(env.domain_b, f"/proxy-ssl/vars.py?name={name}")
|
r = env.tls_get(env.domain_b, f"/proxy-ssl/vars.py?name={name}")
|
||||||
assert r.exit_code == 0, r.stderr
|
assert r.exit_code == 0, r.stderr
|
||||||
assert r.json == {name: value}, r.stdout
|
assert r.json == {name: value}, r.stdout
|
||||||
@ -78,7 +102,21 @@ class TestProxySSL:
|
|||||||
("SSL_VERSION_INTERFACE", r'mod_tls/\d+\.\d+\.\d+'),
|
("SSL_VERSION_INTERFACE", r'mod_tls/\d+\.\d+\.\d+'),
|
||||||
("SSL_VERSION_LIBRARY", r'rustls-ffi/\d+\.\d+\.\d+/rustls/\d+\.\d+\.\d+'),
|
("SSL_VERSION_LIBRARY", r'rustls-ffi/\d+\.\d+\.\d+/rustls/\d+\.\d+\.\d+'),
|
||||||
])
|
])
|
||||||
def test_tls_14_proxy_ssl_vars_match(self, env, name: str, pattern: str):
|
def test_tls_14_proxy_tsl_vars_match(self, env, name: str, pattern: str):
|
||||||
|
if not HttpdTestEnv.has_shared_module("tls"):
|
||||||
|
return
|
||||||
|
r = env.tls_get(env.domain_b, f"/proxy-ssl/vars.py?name={name}")
|
||||||
|
assert r.exit_code == 0, r.stderr
|
||||||
|
assert name in r.json
|
||||||
|
assert re.match(pattern, r.json[name]), r.json
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("name, pattern", [
|
||||||
|
("SSL_VERSION_INTERFACE", r'mod_ssl/\d+\.\d+\.\d+'),
|
||||||
|
("SSL_VERSION_LIBRARY", r'OpenSSL/\d+\.\d+\.\d+'),
|
||||||
|
])
|
||||||
|
def test_tls_14_proxy_ssl_vars_match(self, env, name: str, pattern: str):
|
||||||
|
if HttpdTestEnv.has_shared_module("tls"):
|
||||||
|
return
|
||||||
r = env.tls_get(env.domain_b, f"/proxy-ssl/vars.py?name={name}")
|
r = env.tls_get(env.domain_b, f"/proxy-ssl/vars.py?name={name}")
|
||||||
assert r.exit_code == 0, r.stderr
|
assert r.exit_code == 0, r.stderr
|
||||||
assert name in r.json
|
assert name in r.json
|
||||||
|
@ -3,7 +3,9 @@ from datetime import timedelta
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from .conf import TlsTestConf
|
from .conf import TlsTestConf
|
||||||
|
from pyhttpd.env import HttpdTestEnv
|
||||||
|
|
||||||
|
@pytest.mark.skipif(condition=not HttpdTestEnv.has_shared_module("tls"), reason="no mod_tls available")
|
||||||
|
|
||||||
class TestProxyTLS:
|
class TestProxyTLS:
|
||||||
|
|
||||||
|
@ -3,6 +3,9 @@ import time
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from .conf import TlsTestConf
|
from .conf import TlsTestConf
|
||||||
|
from pyhttpd.env import HttpdTestEnv
|
||||||
|
|
||||||
|
@pytest.mark.skipif(condition=not HttpdTestEnv.has_shared_module("tls"), reason="no mod_tls available")
|
||||||
|
|
||||||
|
|
||||||
class TestProxyMixed:
|
class TestProxyMixed:
|
||||||
|
@ -3,8 +3,9 @@ import os
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from .conf import TlsTestConf
|
from .conf import TlsTestConf
|
||||||
|
from pyhttpd.env import HttpdTestEnv
|
||||||
|
|
||||||
|
@pytest.mark.skipif(condition=not HttpdTestEnv.has_shared_module("tls"), reason="no mod_tls available")
|
||||||
class TestProxyMachineCert:
|
class TestProxyMachineCert:
|
||||||
|
|
||||||
@pytest.fixture(autouse=True, scope='class')
|
@pytest.fixture(autouse=True, scope='class')
|
||||||
|
@ -26,15 +26,96 @@ class HttpdConf(object):
|
|||||||
def install(self):
|
def install(self):
|
||||||
self.env.install_test_conf(self._lines)
|
self.env.install_test_conf(self._lines)
|
||||||
|
|
||||||
|
def replacetlsstr(self, line):
|
||||||
|
l = line.replace("TLS_", "")
|
||||||
|
l = l.replace("\n", " ")
|
||||||
|
l = l.replace("\\", " ")
|
||||||
|
l = " ".join(l.split())
|
||||||
|
l = l.replace(" ", ":")
|
||||||
|
l = l.replace("_", "-")
|
||||||
|
l = l.replace("-WITH", "")
|
||||||
|
l = l.replace("AES-", "AES")
|
||||||
|
l = l.replace("POLY1305-SHA256", "POLY1305")
|
||||||
|
return l
|
||||||
|
|
||||||
|
def replaceinstr(self, line):
|
||||||
|
if line.startswith("TLSCiphersPrefer"):
|
||||||
|
# the "TLS_" are changed into "".
|
||||||
|
l = self.replacetlsstr(line)
|
||||||
|
l = l.replace("TLSCiphersPrefer:", "SSLCipherSuite ")
|
||||||
|
elif line.startswith("TLSCiphersSuppress"):
|
||||||
|
# like SSLCipherSuite but with :!
|
||||||
|
l = self.replacetlsstr(line)
|
||||||
|
l = l.replace("TLSCiphersSuppress:", "SSLCipherSuite !")
|
||||||
|
l = l.replace(":", ":!")
|
||||||
|
elif line.startswith("TLSCertificate"):
|
||||||
|
l = line.replace("TLSCertificate", "SSLCertificateFile")
|
||||||
|
elif line.startswith("TLSProtocol"):
|
||||||
|
# mod_ssl is different (+ no supported and 0x code have to be translated)
|
||||||
|
l = line.replace("TLSProtocol", "SSLProtocol")
|
||||||
|
l = l.replace("+", "")
|
||||||
|
l = l.replace("default", "all")
|
||||||
|
l = l.replace("0x0303", "1.2") # need to check 1.3 and 1.1
|
||||||
|
elif line.startswith("SSLProtocol"):
|
||||||
|
l = line # we have that in test/modules/tls/test_05_proto.py
|
||||||
|
elif line.startswith("TLSHonorClientOrder"):
|
||||||
|
# mod_ssl has SSLHonorCipherOrder on = use server off = use client.
|
||||||
|
l = line.lower()
|
||||||
|
if "on" in l:
|
||||||
|
l = "SSLHonorCipherOrder off"
|
||||||
|
else:
|
||||||
|
l = "SSLHonorCipherOrder on"
|
||||||
|
elif line.startswith("TLSEngine"):
|
||||||
|
# In fact it should go in the corresponding VirtualHost... Not sure how to do that.
|
||||||
|
l = "SSLEngine On"
|
||||||
|
else:
|
||||||
|
if line != "":
|
||||||
|
l = line.replace("TLS", "SSL")
|
||||||
|
else:
|
||||||
|
l = line
|
||||||
|
return l
|
||||||
|
|
||||||
def add(self, line: Any):
|
def add(self, line: Any):
|
||||||
|
# make we transform the TLS to SSL if we are using mod_ssl
|
||||||
if isinstance(line, str):
|
if isinstance(line, str):
|
||||||
|
if not HttpdTestEnv.has_shared_module("tls"):
|
||||||
|
line = self.replaceinstr(line)
|
||||||
if self._indents > 0:
|
if self._indents > 0:
|
||||||
line = f"{' ' * self._indents}{line}"
|
line = f"{' ' * self._indents}{line}"
|
||||||
self._lines.append(line)
|
self._lines.append(line)
|
||||||
else:
|
else:
|
||||||
if self._indents > 0:
|
if not HttpdTestEnv.has_shared_module("tls"):
|
||||||
line = [f"{' ' * self._indents}{l}" for l in line]
|
new = []
|
||||||
self._lines.extend(line)
|
previous = ""
|
||||||
|
for l in line:
|
||||||
|
if previous.startswith("SSLCipherSuite"):
|
||||||
|
if l.startswith("TLSCiphersPrefer") or l.startswith("TLSCiphersSuppress"):
|
||||||
|
# we need to merge it
|
||||||
|
l = self.replaceinstr(l)
|
||||||
|
l = l.replace("SSLCipherSuite ", ":")
|
||||||
|
previous = previous + l
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
if self._indents > 0:
|
||||||
|
previous = f"{' ' * self._indents}{previous}"
|
||||||
|
new.append(previous)
|
||||||
|
previous = ""
|
||||||
|
l = self.replaceinstr(l)
|
||||||
|
if l.startswith("SSLCipherSuite"):
|
||||||
|
previous = l
|
||||||
|
continue
|
||||||
|
if self._indents > 0:
|
||||||
|
l = f"{' ' * self._indents}{l}"
|
||||||
|
new.append(l)
|
||||||
|
if previous != "":
|
||||||
|
if self._indents > 0:
|
||||||
|
previous = f"{' ' * self._indents}{previous}"
|
||||||
|
new.append(previous)
|
||||||
|
self._lines.extend(new)
|
||||||
|
else:
|
||||||
|
if self._indents > 0:
|
||||||
|
line = [f"{' ' * self._indents}{l}" for l in line]
|
||||||
|
self._lines.extend(line)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def add_certificate(self, cert_file, key_file, ssl_module=None):
|
def add_certificate(self, cert_file, key_file, ssl_module=None):
|
||||||
|
Reference in New Issue
Block a user