blob: 0e8ed377e9c3f3772b1b80e1834deaa9ec57dfcd [file]
import hashlib
import inspect
import logging
import os
from typing import List, Optional
from pyhttpd.env import HttpdTestEnv, HttpdTestSetup
from pyhttpd.result import ExecResult
log = logging.getLogger(__name__)
class AAATestSetup(HttpdTestSetup):
def __init__(self, env: 'HttpdTestEnv'):
super().__init__(env=env)
self.add_source_dir(os.path.dirname(inspect.getfile(AAATestSetup)))
self.add_modules(["auth_digest", "authn_file", "authn_core",
"authz_core", "authz_user"])
class AAATestEnv(HttpdTestEnv):
REALM = "AAA Digest Realm"
DIGEST_USER = "digestuser"
DIGEST_PASSWORD = "digestpass2617"
DIGEST_USER2 = "otheruser"
DIGEST_PASSWORD2 = "otherpass2617"
def __init__(self, pytestconfig=None):
super().__init__(pytestconfig=pytestconfig)
self.add_httpd_log_modules(["auth_digest", "authn_file", "authz_core"])
self._digest_pwfile = os.path.join(self.server_dir, "digest.passwd")
def setup_httpd(self, setup: HttpdTestSetup = None):
super().setup_httpd(setup=AAATestSetup(env=self))
self._write_digest_pwfile()
def _write_digest_pwfile(self):
def ha1(user, password):
return hashlib.md5(
f"{user}:{self.REALM}:{password}".encode()).hexdigest()
with open(self._digest_pwfile, 'w') as fd:
fd.write(f"{self.DIGEST_USER}:{self.REALM}:"
f"{ha1(self.DIGEST_USER, self.DIGEST_PASSWORD)}\n")
fd.write(f"{self.DIGEST_USER2}:{self.REALM}:"
f"{ha1(self.DIGEST_USER2, self.DIGEST_PASSWORD2)}\n")
@property
def digest_pwfile(self) -> str:
return self._digest_pwfile
def configtest(self, directory_lines: List[str], extra_top_lines: Optional[List[str]] = None
) -> ExecResult:
"""Run `httpd -t` against a minimal, standalone config built from the
already-generated modules.conf plus `directory_lines` wrapped in a
<Directory> block over the shared docroot. Used to test directives
that are rejected at config-check time (e.g. AuthDigestQop values
other than 'auth') without touching the package's running server.
"""
conf_path = os.path.join(self.gen_dir, "digest-configtest.conf")
modules_conf = os.path.join(self.server_conf_dir, "modules.conf")
lines = [
f'ServerRoot "{self.server_dir}"',
f'Include "{modules_conf}"',
f'DocumentRoot "{self.server_docs_dir}"',
f'Listen {self.http_port2}',
]
if extra_top_lines:
lines.extend(extra_top_lines)
lines.append(f'<Directory "{self.server_docs_dir}">')
lines.extend(f" {l}" for l in directory_lines)
lines.append('</Directory>')
with open(conf_path, 'w') as fd:
fd.write('\n'.join(lines))
fd.write('\n')
httpd_bin = os.path.join(self.bin_dir, 'httpd')
return self.run([httpd_bin, '-t', '-f', conf_path])