mirror of
https://github.com/certbot/certbot.git
synced 2026-01-26 07:41:33 +03:00
This PR is the second part of #6497 to ease the integration, following the new plan propose by @bmw here: #6497 (comment) This PR creates the module certbot.compat.os, that delegates everything to os, and that will be the safeguard against problematic methods of the standard module. On top of that, a quality check wrapper is called in the lint tox environment. This wrapper calls pylint and ensures that standard os module is no used directly in the certbot codebase. Finally local oldest requirements are updated to ensure that tests will take the new logic when running. * Add executable permissions * Add the delegate certbot.compat.os module, add check coding style to enforce usage of certbot.compat.os instead of standard os * Load certbot.compat.os instead of os * Move existing compat test * Update local oldest requirements * Import sys * Update account_test.py * Update os.py * Update os.py * Update local oldest requirements * Implement the new linter_plugin * Fix local oldest for nginx * Remove check coding style * Update linter_plugin.py * Add several comments * Update the setup.py * Add documentation * Update acme dependencies * Update certbot/compat/os.py * Update docs/contributing.rst * Update linter_plugin.py * Handle os.path. Simplify checker. * Add a comment to a reference implementation * Update changelog * Fix module registering * Update docs/contributing.rst * Update config and changelog
233 lines
9.3 KiB
Python
233 lines
9.3 KiB
Python
"""Test for certbot_apache.http_01."""
|
|
import unittest
|
|
import mock
|
|
|
|
from acme import challenges
|
|
from acme.magic_typing import List # pylint: disable=unused-import, no-name-in-module
|
|
|
|
from certbot import achallenges
|
|
from certbot import errors
|
|
from certbot.compat import os
|
|
from certbot.tests import acme_util
|
|
|
|
from certbot_apache.parser import get_aug_path
|
|
from certbot_apache.tests import util
|
|
|
|
|
|
NUM_ACHALLS = 3
|
|
|
|
|
|
class ApacheHttp01Test(util.ApacheTest):
|
|
"""Test for certbot_apache.http_01.ApacheHttp01."""
|
|
|
|
def setUp(self, *args, **kwargs): # pylint: disable=arguments-differ
|
|
super(ApacheHttp01Test, self).setUp(*args, **kwargs)
|
|
|
|
self.account_key = self.rsa512jwk
|
|
self.achalls = [] # type: List[achallenges.KeyAuthorizationAnnotatedChallenge]
|
|
vh_truth = util.get_vh_truth(
|
|
self.temp_dir, "debian_apache_2_4/multiple_vhosts")
|
|
# Takes the vhosts for encryption-example.demo, certbot.demo
|
|
# and vhost.in.rootconf
|
|
self.vhosts = [vh_truth[0], vh_truth[3], vh_truth[10]]
|
|
|
|
for i in range(NUM_ACHALLS):
|
|
self.achalls.append(
|
|
achallenges.KeyAuthorizationAnnotatedChallenge(
|
|
challb=acme_util.chall_to_challb(
|
|
challenges.HTTP01(token=((chr(ord('a') + i).encode() * 16))),
|
|
"pending"),
|
|
domain=self.vhosts[i].name, account_key=self.account_key))
|
|
|
|
modules = ["ssl", "rewrite", "authz_core", "authz_host"]
|
|
for mod in modules:
|
|
self.config.parser.modules.add("mod_{0}.c".format(mod))
|
|
self.config.parser.modules.add(mod + "_module")
|
|
|
|
from certbot_apache.http_01 import ApacheHttp01
|
|
self.http = ApacheHttp01(self.config)
|
|
|
|
def test_empty_perform(self):
|
|
self.assertFalse(self.http.perform())
|
|
|
|
@mock.patch("certbot_apache.configurator.ApacheConfigurator.enable_mod")
|
|
def test_enable_modules_apache_2_2(self, mock_enmod):
|
|
self.config.version = (2, 2)
|
|
self.config.parser.modules.remove("authz_host_module")
|
|
self.config.parser.modules.remove("mod_authz_host.c")
|
|
|
|
enmod_calls = self.common_enable_modules_test(mock_enmod)
|
|
self.assertEqual(enmod_calls[0][0][0], "authz_host")
|
|
|
|
@mock.patch("certbot_apache.configurator.ApacheConfigurator.enable_mod")
|
|
def test_enable_modules_apache_2_4(self, mock_enmod):
|
|
self.config.parser.modules.remove("authz_core_module")
|
|
self.config.parser.modules.remove("mod_authz_core.c")
|
|
|
|
enmod_calls = self.common_enable_modules_test(mock_enmod)
|
|
self.assertEqual(enmod_calls[0][0][0], "authz_core")
|
|
|
|
def common_enable_modules_test(self, mock_enmod):
|
|
"""Tests enabling mod_rewrite and other modules."""
|
|
self.config.parser.modules.remove("rewrite_module")
|
|
self.config.parser.modules.remove("mod_rewrite.c")
|
|
|
|
self.http.prepare_http01_modules()
|
|
|
|
self.assertTrue(mock_enmod.called)
|
|
calls = mock_enmod.call_args_list
|
|
other_calls = []
|
|
for call in calls:
|
|
if call[0][0] != "rewrite":
|
|
other_calls.append(call)
|
|
|
|
# If these lists are equal, we never enabled mod_rewrite
|
|
self.assertNotEqual(calls, other_calls)
|
|
return other_calls
|
|
|
|
def test_same_vhost(self):
|
|
vhost = next(v for v in self.config.vhosts if v.name == "certbot.demo")
|
|
achalls = [
|
|
achallenges.KeyAuthorizationAnnotatedChallenge(
|
|
challb=acme_util.chall_to_challb(
|
|
challenges.HTTP01(token=((b'a' * 16))),
|
|
"pending"),
|
|
domain=vhost.name, account_key=self.account_key),
|
|
achallenges.KeyAuthorizationAnnotatedChallenge(
|
|
challb=acme_util.chall_to_challb(
|
|
challenges.HTTP01(token=((b'b' * 16))),
|
|
"pending"),
|
|
domain=next(iter(vhost.aliases)), account_key=self.account_key)
|
|
]
|
|
self.common_perform_test(achalls, [vhost])
|
|
|
|
def test_anonymous_vhost(self):
|
|
vhosts = [v for v in self.config.vhosts if not v.ssl]
|
|
achalls = [
|
|
achallenges.KeyAuthorizationAnnotatedChallenge(
|
|
challb=acme_util.chall_to_challb(
|
|
challenges.HTTP01(token=((b'a' * 16))),
|
|
"pending"),
|
|
domain="something.nonexistent", account_key=self.account_key)]
|
|
self.common_perform_test(achalls, vhosts)
|
|
|
|
def test_configure_multiple_vhosts(self):
|
|
vhosts = [v for v in self.config.vhosts if "duplicate.example.com" in v.get_names()]
|
|
self.assertEqual(len(vhosts), 2)
|
|
achalls = [
|
|
achallenges.KeyAuthorizationAnnotatedChallenge(
|
|
challb=acme_util.chall_to_challb(
|
|
challenges.HTTP01(token=((b'a' * 16))),
|
|
"pending"),
|
|
domain="duplicate.example.com", account_key=self.account_key)]
|
|
self.common_perform_test(achalls, vhosts)
|
|
|
|
def test_no_vhost(self):
|
|
for achall in self.achalls:
|
|
self.http.add_chall(achall)
|
|
self.config.config.http01_port = 12345
|
|
self.assertRaises(errors.PluginError, self.http.perform)
|
|
|
|
def test_perform_1_achall_apache_2_2(self):
|
|
self.combinations_perform_test(num_achalls=1, minor_version=2)
|
|
|
|
def test_perform_1_achall_apache_2_4(self):
|
|
self.combinations_perform_test(num_achalls=1, minor_version=4)
|
|
|
|
def test_perform_2_achall_apache_2_2(self):
|
|
self.combinations_perform_test(num_achalls=2, minor_version=2)
|
|
|
|
def test_perform_2_achall_apache_2_4(self):
|
|
self.combinations_perform_test(num_achalls=2, minor_version=4)
|
|
|
|
def test_perform_3_achall_apache_2_2(self):
|
|
self.combinations_perform_test(num_achalls=3, minor_version=2)
|
|
|
|
def test_perform_3_achall_apache_2_4(self):
|
|
self.combinations_perform_test(num_achalls=3, minor_version=4)
|
|
|
|
def test_activate_disabled_vhost(self):
|
|
vhosts = [v for v in self.config.vhosts if v.name == "certbot.demo"]
|
|
achalls = [
|
|
achallenges.KeyAuthorizationAnnotatedChallenge(
|
|
challb=acme_util.chall_to_challb(
|
|
challenges.HTTP01(token=((b'a' * 16))),
|
|
"pending"),
|
|
domain="certbot.demo", account_key=self.account_key)]
|
|
vhosts[0].enabled = False
|
|
self.common_perform_test(achalls, vhosts)
|
|
matches = self.config.parser.find_dir(
|
|
"Include", vhosts[0].filep,
|
|
get_aug_path(self.config.parser.loc["default"]))
|
|
self.assertEqual(len(matches), 1)
|
|
|
|
def combinations_perform_test(self, num_achalls, minor_version):
|
|
"""Test perform with the given achall count and Apache version."""
|
|
achalls = self.achalls[:num_achalls]
|
|
vhosts = self.vhosts[:num_achalls]
|
|
self.config.version = (2, minor_version)
|
|
self.common_perform_test(achalls, vhosts)
|
|
|
|
def common_perform_test(self, achalls, vhosts):
|
|
"""Tests perform with the given achalls."""
|
|
challenge_dir = self.http.challenge_dir
|
|
self.assertFalse(os.path.exists(challenge_dir))
|
|
for achall in achalls:
|
|
self.http.add_chall(achall)
|
|
|
|
expected_response = [
|
|
achall.response(self.account_key) for achall in achalls]
|
|
self.assertEqual(self.http.perform(), expected_response)
|
|
|
|
self.assertTrue(os.path.isdir(self.http.challenge_dir))
|
|
self._has_min_permissions(self.http.challenge_dir, 0o755)
|
|
self._test_challenge_conf()
|
|
|
|
for achall in achalls:
|
|
self._test_challenge_file(achall)
|
|
|
|
for vhost in vhosts:
|
|
matches = self.config.parser.find_dir("Include",
|
|
self.http.challenge_conf_pre,
|
|
vhost.path)
|
|
self.assertEqual(len(matches), 1)
|
|
matches = self.config.parser.find_dir("Include",
|
|
self.http.challenge_conf_post,
|
|
vhost.path)
|
|
self.assertEqual(len(matches), 1)
|
|
|
|
self.assertTrue(os.path.exists(challenge_dir))
|
|
|
|
def _test_challenge_conf(self):
|
|
with open(self.http.challenge_conf_pre) as f:
|
|
pre_conf_contents = f.read()
|
|
|
|
with open(self.http.challenge_conf_post) as f:
|
|
post_conf_contents = f.read()
|
|
|
|
self.assertTrue("RewriteEngine on" in pre_conf_contents)
|
|
self.assertTrue("RewriteRule" in pre_conf_contents)
|
|
|
|
self.assertTrue(self.http.challenge_dir in post_conf_contents)
|
|
if self.config.version < (2, 4):
|
|
self.assertTrue("Allow from all" in post_conf_contents)
|
|
else:
|
|
self.assertTrue("Require all granted" in post_conf_contents)
|
|
|
|
def _test_challenge_file(self, achall):
|
|
name = os.path.join(self.http.challenge_dir, achall.chall.encode("token"))
|
|
validation = achall.validation(self.account_key)
|
|
|
|
self._has_min_permissions(name, 0o644)
|
|
with open(name, 'rb') as f:
|
|
self.assertEqual(f.read(), validation.encode())
|
|
|
|
def _has_min_permissions(self, path, min_mode):
|
|
"""Tests the given file has at least the permissions in mode."""
|
|
st_mode = os.stat(path).st_mode
|
|
self.assertEqual(st_mode, st_mode | min_mode)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main() # pragma: no cover
|