mirror of
https://github.com/certbot/certbot.git
synced 2026-06-04 22:33:00 -04:00
314 lines
14 KiB
Python
314 lines
14 KiB
Python
"""Tests for certbot_postfix.installer."""
|
|
from contextlib import contextmanager
|
|
import copy
|
|
import functools
|
|
import os
|
|
import pkg_resources
|
|
import six
|
|
import unittest
|
|
|
|
import mock
|
|
|
|
from certbot import errors
|
|
from certbot.tests import util as certbot_test_util
|
|
|
|
# pylint: disable=unused-import, no-name-in-module
|
|
from acme.magic_typing import Dict, Tuple, Union
|
|
# pylint: enable=unused-import, no-name-in-module
|
|
|
|
DEFAULT_MAIN_CF = {
|
|
"smtpd_tls_cert_file": "",
|
|
"smtpd_tls_key_file": "",
|
|
"smtpd_tls_dh1024_param_file": "",
|
|
"smtpd_tls_security_level": "none",
|
|
"smtpd_tls_auth_only": "",
|
|
"smtpd_tls_mandatory_protocols": "",
|
|
"smtpd_tls_protocols": "",
|
|
"smtpd_tls_ciphers": "",
|
|
"smtpd_tls_exclude_ciphers": "",
|
|
"smtpd_tls_mandatory_ciphers": "",
|
|
"smtpd_tls_eecdh_grade": "medium",
|
|
"smtp_tls_security_level": "",
|
|
"smtp_tls_ciphers": "",
|
|
"smtp_tls_exclude_ciphers": "",
|
|
"smtp_tls_mandatory_ciphers": "",
|
|
"mail_version": "3.2.3"
|
|
}
|
|
|
|
def _main_cf_with(obj):
|
|
main_cf = copy.copy(DEFAULT_MAIN_CF)
|
|
main_cf.update(obj)
|
|
return main_cf
|
|
|
|
class InstallerTest(certbot_test_util.ConfigTestCase):
|
|
# pylint: disable=too-many-public-methods
|
|
|
|
def setUp(self):
|
|
super(InstallerTest, self).setUp()
|
|
_config_file = pkg_resources.resource_filename("certbot_postfix.tests",
|
|
os.path.join("testdata", "config.json"))
|
|
self.config.postfix_ctl = "postfix"
|
|
self.config.postfix_config_dir = self.tempdir
|
|
self.config.postfix_config_utility = "postconf"
|
|
self.config.postfix_tls_only = False
|
|
self.config.postfix_server_only = False
|
|
self.config.config_dir = self.tempdir
|
|
|
|
@mock.patch("certbot_postfix.installer.util.is_acceptable_value")
|
|
def test_set_vars(self, mock_is_acceptable_value):
|
|
mock_is_acceptable_value.return_value = True
|
|
with create_installer(self.config) as installer:
|
|
installer.prepare()
|
|
mock_is_acceptable_value.return_value = False
|
|
|
|
@mock.patch("certbot_postfix.installer.util.is_acceptable_value")
|
|
def test_acceptable_value(self, mock_is_acceptable_value):
|
|
mock_is_acceptable_value.return_value = True
|
|
with create_installer(self.config) as installer:
|
|
installer.prepare()
|
|
mock_is_acceptable_value.return_value = False
|
|
|
|
@certbot_test_util.patch_get_utility()
|
|
def test_confirm_changes_no_raises_error(self, mock_util):
|
|
mock_util().yesno.return_value = False
|
|
with create_installer(self.config) as installer:
|
|
installer.prepare()
|
|
self.assertRaises(errors.PluginError, installer.deploy_cert,
|
|
"example.com", "cert_path", "key_path",
|
|
"chain_path", "fullchain_path")
|
|
|
|
@certbot_test_util.patch_get_utility()
|
|
def test_save(self, mock_util):
|
|
mock_util().yesno.return_value = True
|
|
with create_installer(self.config) as installer:
|
|
installer.prepare()
|
|
installer.postconf.flush = mock.Mock()
|
|
installer.reverter = mock.Mock()
|
|
installer.deploy_cert("example.com", "cert_path", "key_path",
|
|
"chain_path", "fullchain_path")
|
|
installer.save()
|
|
self.assertEqual(installer.save_notes, [])
|
|
self.assertEqual(installer.postconf.flush.call_count, 1)
|
|
self.assertEqual(installer.reverter.add_to_checkpoint.call_count, 1)
|
|
|
|
@certbot_test_util.patch_get_utility()
|
|
def test_save_with_title(self, mock_util):
|
|
mock_util().yesno.return_value = True
|
|
with create_installer(self.config) as installer:
|
|
installer.prepare()
|
|
installer.postconf.flush = mock.Mock()
|
|
installer.reverter = mock.Mock()
|
|
installer.deploy_cert("example.com", "cert_path", "key_path",
|
|
"chain_path", "fullchain_path")
|
|
installer.save(title="new_file!")
|
|
self.assertEqual(installer.reverter.finalize_checkpoint.call_count, 1)
|
|
|
|
@certbot_test_util.patch_get_utility()
|
|
def test_rollback_checkpoints_resets_postconf(self, mock_util):
|
|
mock_util().yesno.return_value = True
|
|
with create_installer(self.config) as installer:
|
|
installer.prepare()
|
|
installer.deploy_cert("example.com", "cert_path", "key_path",
|
|
"chain_path", "fullchain_path")
|
|
installer.rollback_checkpoints()
|
|
self.assertEqual(installer.postconf.get_changes(), {})
|
|
|
|
@certbot_test_util.patch_get_utility()
|
|
def test_recovery_routine_resets_postconf(self, mock_util):
|
|
mock_util().yesno.return_value = True
|
|
with create_installer(self.config) as installer:
|
|
installer.prepare()
|
|
installer.deploy_cert("example.com", "cert_path", "key_path",
|
|
"chain_path", "fullchain_path")
|
|
installer.recovery_routine()
|
|
self.assertEqual(installer.postconf.get_changes(), {})
|
|
|
|
def test_restart(self):
|
|
with create_installer(self.config) as installer:
|
|
installer.prepare()
|
|
installer.restart()
|
|
self.assertEqual(installer.postfix.restart.call_count, 1)
|
|
|
|
def test_add_parser_arguments(self):
|
|
options = set(("ctl", "config-dir", "config-utility",
|
|
"tls-only", "server-only", "ignore-master-overrides"))
|
|
mock_add = mock.MagicMock()
|
|
|
|
from certbot_postfix import installer
|
|
installer.Installer.add_parser_arguments(mock_add)
|
|
|
|
for call in mock_add.call_args_list:
|
|
self.assertTrue(call[0][0] in options)
|
|
|
|
def test_no_postconf_prepare(self):
|
|
with create_installer(self.config) as installer:
|
|
installer_path = "certbot_postfix.installer"
|
|
exe_exists_path = installer_path + ".certbot_util.exe_exists"
|
|
path_surgery_path = "certbot_postfix.util.plugins_util.path_surgery"
|
|
with mock.patch(path_surgery_path, return_value=False):
|
|
with mock.patch(exe_exists_path, return_value=False):
|
|
self.assertRaises(errors.NoInstallationError,
|
|
installer.prepare)
|
|
|
|
def test_old_version(self):
|
|
with create_installer(self.config, main_cf=_main_cf_with({"mail_version": "0.0.1"}))\
|
|
as installer:
|
|
self.assertRaises(errors.NotSupportedError, installer.prepare)
|
|
|
|
def test_lock_error(self):
|
|
with create_installer(self.config) as installer:
|
|
assert_raises = functools.partial(self.assertRaises,
|
|
errors.PluginError,
|
|
installer.prepare)
|
|
certbot_test_util.lock_and_call(assert_raises, self.tempdir)
|
|
|
|
|
|
@mock.patch('certbot.util.lock_dir_until_exit')
|
|
def test_dir_locked(self, lock_dir):
|
|
with create_installer(self.config) as installer:
|
|
lock_dir.side_effect = errors.LockError
|
|
self.assertRaises(errors.PluginError, installer.prepare)
|
|
|
|
def test_more_info(self):
|
|
with create_installer(self.config) as installer:
|
|
installer.prepare()
|
|
output = installer.more_info()
|
|
self.assertTrue("Postfix" in output)
|
|
self.assertTrue(self.tempdir in output)
|
|
self.assertTrue(DEFAULT_MAIN_CF["mail_version"] in output)
|
|
|
|
def test_get_all_names(self):
|
|
config = {"mydomain": "example.org",
|
|
"myhostname": "mail.example.org",
|
|
"myorigin": "example.org"}
|
|
with create_installer(self.config, main_cf=_main_cf_with(config)) as installer:
|
|
installer.prepare()
|
|
result = installer.get_all_names()
|
|
self.assertEqual(result, set(config.values()))
|
|
|
|
@certbot_test_util.patch_get_utility()
|
|
def test_deploy(self, mock_util):
|
|
mock_util().yesno.return_value = True
|
|
from certbot_postfix import constants
|
|
with create_installer(self.config) as installer:
|
|
installer.prepare()
|
|
|
|
# pylint: disable=protected-access
|
|
installer.deploy_cert("example.com", "cert_path", "key_path",
|
|
"chain_path", "fullchain_path")
|
|
changes = installer.postconf.get_changes()
|
|
expected = {} # type: Dict[str, Tuple[str, ...]]
|
|
expected.update(constants.TLS_SERVER_VARS)
|
|
expected.update(constants.DEFAULT_SERVER_VARS)
|
|
expected.update(constants.DEFAULT_CLIENT_VARS)
|
|
self.assertEqual(changes["smtpd_tls_key_file"], "key_path")
|
|
self.assertEqual(changes["smtpd_tls_cert_file"], "cert_path")
|
|
for name, value in six.iteritems(expected):
|
|
self.assertEqual(changes[name], value[0])
|
|
|
|
@certbot_test_util.patch_get_utility()
|
|
def test_tls_only(self, mock_util):
|
|
mock_util().yesno.return_value = True
|
|
with create_installer(self.config) as installer:
|
|
installer.prepare()
|
|
installer.conf = lambda x: x == "tls_only"
|
|
installer.postconf.set = mock.Mock()
|
|
installer.deploy_cert("example.com", "cert_path", "key_path",
|
|
"chain_path", "fullchain_path")
|
|
self.assertEqual(installer.postconf.set.call_count, 4)
|
|
|
|
@certbot_test_util.patch_get_utility()
|
|
def test_server_only(self, mock_util):
|
|
mock_util().yesno.return_value = True
|
|
with create_installer(self.config) as installer:
|
|
installer.prepare()
|
|
installer.conf = lambda x: x == "server_only"
|
|
installer.postconf.set = mock.Mock()
|
|
installer.deploy_cert("example.com", "cert_path", "key_path",
|
|
"chain_path", "fullchain_path")
|
|
self.assertEqual(installer.postconf.set.call_count, 11)
|
|
|
|
@certbot_test_util.patch_get_utility()
|
|
def test_tls_and_server_only(self, mock_util):
|
|
mock_util().yesno.return_value = True
|
|
with create_installer(self.config) as installer:
|
|
installer.prepare()
|
|
installer.conf = lambda x: True
|
|
installer.postconf.set = mock.Mock()
|
|
installer.deploy_cert("example.com", "cert_path", "key_path",
|
|
"chain_path", "fullchain_path")
|
|
self.assertEqual(installer.postconf.set.call_count, 3)
|
|
|
|
@certbot_test_util.patch_get_utility()
|
|
def test_deploy_twice(self, mock_util):
|
|
# Deploying twice on the same installer shouldn't do anything!
|
|
mock_util().yesno.return_value = True
|
|
with create_installer(self.config) as installer:
|
|
installer.prepare()
|
|
from certbot_postfix.postconf import ConfigMain
|
|
with mock.patch.object(ConfigMain, "set", wraps=installer.postconf.set) as fake_set:
|
|
installer.deploy_cert("example.com", "cert_path", "key_path",
|
|
"chain_path", "fullchain_path")
|
|
self.assertEqual(fake_set.call_count, 15)
|
|
fake_set.reset_mock()
|
|
installer.deploy_cert("example.com", "cert_path", "key_path",
|
|
"chain_path", "fullchain_path")
|
|
self.assertFalse(fake_set.called)
|
|
|
|
@certbot_test_util.patch_get_utility()
|
|
def test_deploy_already_secure(self, mock_util):
|
|
# Should not overwrite "more-secure" parameters
|
|
mock_util().yesno.return_value = True
|
|
more_secure = {
|
|
"smtpd_tls_security_level": "encrypt",
|
|
"smtpd_tls_protocols": "!SSLv3, !SSLv2, !TLSv1",
|
|
"smtpd_tls_eecdh_grade": "strong"
|
|
}
|
|
with create_installer(self.config,\
|
|
main_cf=_main_cf_with(more_secure)) as installer:
|
|
installer.prepare()
|
|
installer.deploy_cert("example.com", "cert_path", "key_path",
|
|
"chain_path", "fullchain_path")
|
|
for param in more_secure.keys():
|
|
self.assertFalse(param in installer.postconf.get_changes())
|
|
|
|
def test_enhance(self):
|
|
with create_installer(self.config) as installer:
|
|
installer.prepare()
|
|
self.assertRaises(errors.PluginError,
|
|
installer.enhance,
|
|
"example.org", "redirect")
|
|
|
|
def test_supported_enhancements(self):
|
|
with create_installer(self.config) as installer:
|
|
installer.prepare()
|
|
self.assertEqual(installer.supported_enhancements(), [])
|
|
|
|
@contextmanager
|
|
def create_installer(config, main_cf=DEFAULT_MAIN_CF):
|
|
# pylint: disable=dangerous-default-value
|
|
"""Creates a Postfix installer with calls to `postconf` and `postfix` mocked out.
|
|
|
|
In particular, creates a ConfigMain object that does regular things, but seeds it
|
|
with values from `main_cf` and `master_cf` dicts.
|
|
"""
|
|
from certbot_postfix.postconf import ConfigMain
|
|
from certbot_postfix import installer
|
|
def _mock_init_postconf(postconf, executable, ignore_master_overrides=False, config_dir=None):
|
|
# pylint: disable=protected-access,unused-argument
|
|
postconf._ignore_master_overrides = ignore_master_overrides
|
|
postconf._db = main_cf
|
|
postconf._master_db = {}
|
|
postconf._updated = {}
|
|
# override get_default to get from main
|
|
postconf.get_default = lambda name: main_cf[name]
|
|
with mock.patch.object(ConfigMain, "__init__", _mock_init_postconf):
|
|
exe_exists_path = "certbot_postfix.installer.certbot_util.exe_exists"
|
|
with mock.patch(exe_exists_path, return_value=True):
|
|
with mock.patch("certbot_postfix.installer.util.PostfixUtil",
|
|
return_value=mock.Mock()):
|
|
yield installer.Installer(config, "postfix")
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main() # pragma: no cover
|
|
|