2019-11-14 17:26:01 -05:00
|
|
|
# pylint: disable=too-many-lines
|
2019-11-25 12:44:40 -05:00
|
|
|
"""Test for certbot_apache._internal.configurator."""
|
2019-03-27 13:10:52 -04:00
|
|
|
import copy
|
2014-12-03 07:35:49 -05:00
|
|
|
import shutil
|
2015-07-24 06:22:35 -04:00
|
|
|
import socket
|
2023-02-13 14:44:42 -05:00
|
|
|
import sys
|
Distribution specific override functionality based on class inheritance (#5202)
Class inheritance based approach to distro specific overrides.
How it works:
The certbot-apache plugin entrypoint has been changed to entrypoint.ENTRYPOINT which is a variable containing appropriate override class for system, if available.
Override classes register themselves using decorator override.register() which takes a list of distribution fingerprints (ID & LIKE variables in /etc/os-release, or platform.linux_distribution() as a fallback). These end up as keys in dict override.OVERRIDE_CLASSES and values for the keys are references to the class that called the decorator, hence allowing self-registration of override classes when they are imported. The only file importing these override classes is entrypoint.py, so adding new override classes would need only one import in addition to the actual override class file.
Generic changes:
Parser initialization has been moved to separate class method, allowing easy override where needed.
Cleaned up configurator.py a bit, and moved some helper functions to newly created apache_util.py
Split Debian specific code from configurator.py to debian_override.py
Changed define_cmd to apache_cmd because the parameters are for every distribution supporting this behavior, and we're able to use the value to build the additional configuration dump commands.
Moved add_parser_mod() from configurator to parser add_mod()
Added two new configuration dump parsing methods to update_runtime_variables() in parser: update_includes() and update_modules().
Changed init_modules() in parser to accommodate the changes above. (ie. don't throw existing self.modules out).
Moved OS based constants to their respective override classes.
Refactored configurator class discovery in tests to help easier test case creation using distribution based override configurator class.
tests.util.get_apache_configurator() now takes keyword argument os_info which is string of the desired mock OS fingerprint response that's used for picking the right override class.
This PR includes two major generic additions that should vastly improve our parsing accuracy and quality:
Includes are parsed from config dump from httpd binary. This is mandatory for some distributions (Like OpenSUSE) to get visibility over the whole configuration tree because of Include statements passed on in command line, and not via root httpd.conf file.
Modules are parsed from config dump from httpd binary. This lets us jump into correct IfModule directives if for some reason we have missed the module availability (because of one being included on command line or such).
Distribution specific changes
Because of the generic changes, there are two distributions (or distribution families) that do not provide such functionality, so it had to be overridden in their respective override files. These distributions are:
CentOS, because it deliberately limits httpd binary stdout using SELinux as a feature. We are doing opportunistic config dumps here however, in case SELinux enforcing is off.
Gentoo, because it does not provide a way to invoke httpd with command line parsed from its specific configuration file. Gentoo relies heavily on Define statements that are passed over from APACHE2_OPTS variable /etc/conf.d/apache2 file and most of the configuration in root Apache configuration are dependent on these values.
Debian
Moved the Debian specific parts from configurator.py to Debian specific override.
CentOS
Parsing of /etc/sysconfig/httpd file for additional Define statements. This could hold other parameters too, but parsing everything off it would require a full Apache lexer. For CLI parameters, I think Defines are the most common ones. This is done in addition of opportunistic parsing of httpd binary config dump.
Added CentOS default Apache configuration tree for realistic test cases.
Gentoo
Parsing Defines from /etc/conf.d/apache2 variable APACHE2_OPTS, which holds additional Define statements to enable certain functionalities, enabling parts of the configuration in the Apache2 DOM. This is done instead of trying to parse httpd binary configuration dumps.
Added default Apache configuration from Gentoo to testdata, including /etc/conf.d/apache2 file for realistic test cases.
* Distribution specific override functionality based on class inheritance
* Need to patch get_systemd_os_like to as travis has proper os-release
* Added pydoc
* Move parser initialization to a method and fix Python 3 __new__ errors
* Parser changes to parse HTTPD config
* Try to get modules and includes from httpd process for better visibility over the configuration
* Had to disable duplicate-code because of test setup (PyCQA/pylint/issues/214)
* CentOS tests and linter fixes
* Gentoo override, tests and linter fixes
* Mock the process call in all the tests that require it
* Fix CentOS test mock
* Restore reseting modules list functionality for cleanup
* Move OS fingerprinting and constant mocks to parent class
* Fixes requested in review
* New entrypoint structure and started moving OS constants to override classes
* OS constants move continued, test and linter fixes
* Removed dead code
* Apache compatibility test changest to reflect OS constant restructure
* Test fix
* Requested changes
* Moved Debian specific tests to own test file
* Removed decorator based override class registration in favor of entrypoint dict
* Fix for update_includes for some versions of Augeas
* Take fedora fix into account in tests
* Review fixes
2017-12-04 14:49:18 -05:00
|
|
|
import tempfile
|
2022-09-28 19:17:03 -04:00
|
|
|
from unittest import mock
|
2014-12-10 07:19:50 -05:00
|
|
|
|
2023-02-13 14:44:42 -05:00
|
|
|
import pytest
|
|
|
|
|
|
2015-05-10 07:26:21 -04:00
|
|
|
from acme import challenges
|
2016-04-13 19:30:57 -04:00
|
|
|
from certbot import achallenges
|
2017-05-23 19:25:39 -04:00
|
|
|
from certbot import crypto_util
|
2016-04-13 19:30:57 -04:00
|
|
|
from certbot import errors
|
2019-06-20 13:52:43 -04:00
|
|
|
from certbot.compat import filesystem
|
2019-12-09 15:50:20 -05:00
|
|
|
from certbot.compat import os
|
2016-04-13 19:30:57 -04:00
|
|
|
from certbot.tests import acme_util
|
2017-01-10 19:25:33 -05:00
|
|
|
from certbot.tests import util as certbot_util
|
2019-11-25 12:44:40 -05:00
|
|
|
from certbot_apache._internal import apache_util
|
|
|
|
|
from certbot_apache._internal import constants
|
|
|
|
|
from certbot_apache._internal import obj
|
|
|
|
|
from certbot_apache._internal import parser
|
2023-03-28 17:55:44 -04:00
|
|
|
from certbot_apache._internal.tests import util
|
2015-04-23 02:17:53 -04:00
|
|
|
|
2014-12-04 07:00:22 -05:00
|
|
|
|
2016-03-20 15:57:52 -04:00
|
|
|
class MultipleVhostsTest(util.ApacheTest):
|
2015-07-19 05:22:10 -04:00
|
|
|
"""Test two standard well-configured HTTP vhosts."""
|
2014-12-09 04:21:56 -05:00
|
|
|
|
2015-07-19 19:48:27 -04:00
|
|
|
def setUp(self): # pylint: disable=arguments-differ
|
2021-04-08 16:04:51 -04:00
|
|
|
super().setUp()
|
2014-12-03 07:35:49 -05:00
|
|
|
|
Distribution specific override functionality based on class inheritance (#5202)
Class inheritance based approach to distro specific overrides.
How it works:
The certbot-apache plugin entrypoint has been changed to entrypoint.ENTRYPOINT which is a variable containing appropriate override class for system, if available.
Override classes register themselves using decorator override.register() which takes a list of distribution fingerprints (ID & LIKE variables in /etc/os-release, or platform.linux_distribution() as a fallback). These end up as keys in dict override.OVERRIDE_CLASSES and values for the keys are references to the class that called the decorator, hence allowing self-registration of override classes when they are imported. The only file importing these override classes is entrypoint.py, so adding new override classes would need only one import in addition to the actual override class file.
Generic changes:
Parser initialization has been moved to separate class method, allowing easy override where needed.
Cleaned up configurator.py a bit, and moved some helper functions to newly created apache_util.py
Split Debian specific code from configurator.py to debian_override.py
Changed define_cmd to apache_cmd because the parameters are for every distribution supporting this behavior, and we're able to use the value to build the additional configuration dump commands.
Moved add_parser_mod() from configurator to parser add_mod()
Added two new configuration dump parsing methods to update_runtime_variables() in parser: update_includes() and update_modules().
Changed init_modules() in parser to accommodate the changes above. (ie. don't throw existing self.modules out).
Moved OS based constants to their respective override classes.
Refactored configurator class discovery in tests to help easier test case creation using distribution based override configurator class.
tests.util.get_apache_configurator() now takes keyword argument os_info which is string of the desired mock OS fingerprint response that's used for picking the right override class.
This PR includes two major generic additions that should vastly improve our parsing accuracy and quality:
Includes are parsed from config dump from httpd binary. This is mandatory for some distributions (Like OpenSUSE) to get visibility over the whole configuration tree because of Include statements passed on in command line, and not via root httpd.conf file.
Modules are parsed from config dump from httpd binary. This lets us jump into correct IfModule directives if for some reason we have missed the module availability (because of one being included on command line or such).
Distribution specific changes
Because of the generic changes, there are two distributions (or distribution families) that do not provide such functionality, so it had to be overridden in their respective override files. These distributions are:
CentOS, because it deliberately limits httpd binary stdout using SELinux as a feature. We are doing opportunistic config dumps here however, in case SELinux enforcing is off.
Gentoo, because it does not provide a way to invoke httpd with command line parsed from its specific configuration file. Gentoo relies heavily on Define statements that are passed over from APACHE2_OPTS variable /etc/conf.d/apache2 file and most of the configuration in root Apache configuration are dependent on these values.
Debian
Moved the Debian specific parts from configurator.py to Debian specific override.
CentOS
Parsing of /etc/sysconfig/httpd file for additional Define statements. This could hold other parameters too, but parsing everything off it would require a full Apache lexer. For CLI parameters, I think Defines are the most common ones. This is done in addition of opportunistic parsing of httpd binary config dump.
Added CentOS default Apache configuration tree for realistic test cases.
Gentoo
Parsing Defines from /etc/conf.d/apache2 variable APACHE2_OPTS, which holds additional Define statements to enable certain functionalities, enabling parts of the configuration in the Apache2 DOM. This is done instead of trying to parse httpd binary configuration dumps.
Added default Apache configuration from Gentoo to testdata, including /etc/conf.d/apache2 file for realistic test cases.
* Distribution specific override functionality based on class inheritance
* Need to patch get_systemd_os_like to as travis has proper os-release
* Added pydoc
* Move parser initialization to a method and fix Python 3 __new__ errors
* Parser changes to parse HTTPD config
* Try to get modules and includes from httpd process for better visibility over the configuration
* Had to disable duplicate-code because of test setup (PyCQA/pylint/issues/214)
* CentOS tests and linter fixes
* Gentoo override, tests and linter fixes
* Mock the process call in all the tests that require it
* Fix CentOS test mock
* Restore reseting modules list functionality for cleanup
* Move OS fingerprinting and constant mocks to parent class
* Fixes requested in review
* New entrypoint structure and started moving OS constants to override classes
* OS constants move continued, test and linter fixes
* Removed dead code
* Apache compatibility test changest to reflect OS constant restructure
* Test fix
* Requested changes
* Moved Debian specific tests to own test file
* Removed decorator based override class registration in favor of entrypoint dict
* Fix for update_includes for some versions of Augeas
* Take fedora fix into account in tests
* Review fixes
2017-12-04 14:49:18 -05:00
|
|
|
self.config = util.get_apache_configurator(
|
|
|
|
|
self.config_path, self.vhost_path, self.config_dir, self.work_dir)
|
|
|
|
|
self.config = self.mock_deploy_cert(self.config)
|
2015-01-24 08:12:45 -05:00
|
|
|
self.vh_truth = util.get_vh_truth(
|
2016-03-20 15:57:52 -04:00
|
|
|
self.temp_dir, "debian_apache_2_4/multiple_vhosts")
|
2014-12-03 07:35:49 -05:00
|
|
|
|
2015-12-09 20:05:38 -05:00
|
|
|
def mock_deploy_cert(self, config):
|
2015-12-21 17:39:14 -05:00
|
|
|
"""A test for a mock deploy cert"""
|
Distribution specific override functionality based on class inheritance (#5202)
Class inheritance based approach to distro specific overrides.
How it works:
The certbot-apache plugin entrypoint has been changed to entrypoint.ENTRYPOINT which is a variable containing appropriate override class for system, if available.
Override classes register themselves using decorator override.register() which takes a list of distribution fingerprints (ID & LIKE variables in /etc/os-release, or platform.linux_distribution() as a fallback). These end up as keys in dict override.OVERRIDE_CLASSES and values for the keys are references to the class that called the decorator, hence allowing self-registration of override classes when they are imported. The only file importing these override classes is entrypoint.py, so adding new override classes would need only one import in addition to the actual override class file.
Generic changes:
Parser initialization has been moved to separate class method, allowing easy override where needed.
Cleaned up configurator.py a bit, and moved some helper functions to newly created apache_util.py
Split Debian specific code from configurator.py to debian_override.py
Changed define_cmd to apache_cmd because the parameters are for every distribution supporting this behavior, and we're able to use the value to build the additional configuration dump commands.
Moved add_parser_mod() from configurator to parser add_mod()
Added two new configuration dump parsing methods to update_runtime_variables() in parser: update_includes() and update_modules().
Changed init_modules() in parser to accommodate the changes above. (ie. don't throw existing self.modules out).
Moved OS based constants to their respective override classes.
Refactored configurator class discovery in tests to help easier test case creation using distribution based override configurator class.
tests.util.get_apache_configurator() now takes keyword argument os_info which is string of the desired mock OS fingerprint response that's used for picking the right override class.
This PR includes two major generic additions that should vastly improve our parsing accuracy and quality:
Includes are parsed from config dump from httpd binary. This is mandatory for some distributions (Like OpenSUSE) to get visibility over the whole configuration tree because of Include statements passed on in command line, and not via root httpd.conf file.
Modules are parsed from config dump from httpd binary. This lets us jump into correct IfModule directives if for some reason we have missed the module availability (because of one being included on command line or such).
Distribution specific changes
Because of the generic changes, there are two distributions (or distribution families) that do not provide such functionality, so it had to be overridden in their respective override files. These distributions are:
CentOS, because it deliberately limits httpd binary stdout using SELinux as a feature. We are doing opportunistic config dumps here however, in case SELinux enforcing is off.
Gentoo, because it does not provide a way to invoke httpd with command line parsed from its specific configuration file. Gentoo relies heavily on Define statements that are passed over from APACHE2_OPTS variable /etc/conf.d/apache2 file and most of the configuration in root Apache configuration are dependent on these values.
Debian
Moved the Debian specific parts from configurator.py to Debian specific override.
CentOS
Parsing of /etc/sysconfig/httpd file for additional Define statements. This could hold other parameters too, but parsing everything off it would require a full Apache lexer. For CLI parameters, I think Defines are the most common ones. This is done in addition of opportunistic parsing of httpd binary config dump.
Added CentOS default Apache configuration tree for realistic test cases.
Gentoo
Parsing Defines from /etc/conf.d/apache2 variable APACHE2_OPTS, which holds additional Define statements to enable certain functionalities, enabling parts of the configuration in the Apache2 DOM. This is done instead of trying to parse httpd binary configuration dumps.
Added default Apache configuration from Gentoo to testdata, including /etc/conf.d/apache2 file for realistic test cases.
* Distribution specific override functionality based on class inheritance
* Need to patch get_systemd_os_like to as travis has proper os-release
* Added pydoc
* Move parser initialization to a method and fix Python 3 __new__ errors
* Parser changes to parse HTTPD config
* Try to get modules and includes from httpd process for better visibility over the configuration
* Had to disable duplicate-code because of test setup (PyCQA/pylint/issues/214)
* CentOS tests and linter fixes
* Gentoo override, tests and linter fixes
* Mock the process call in all the tests that require it
* Fix CentOS test mock
* Restore reseting modules list functionality for cleanup
* Move OS fingerprinting and constant mocks to parent class
* Fixes requested in review
* New entrypoint structure and started moving OS constants to override classes
* OS constants move continued, test and linter fixes
* Removed dead code
* Apache compatibility test changest to reflect OS constant restructure
* Test fix
* Requested changes
* Moved Debian specific tests to own test file
* Removed decorator based override class registration in favor of entrypoint dict
* Fix for update_includes for some versions of Augeas
* Take fedora fix into account in tests
* Review fixes
2017-12-04 14:49:18 -05:00
|
|
|
config.real_deploy_cert = self.config.deploy_cert
|
2016-01-14 06:25:15 -05:00
|
|
|
|
2015-12-09 20:05:38 -05:00
|
|
|
def mocked_deploy_cert(*args, **kwargs):
|
2015-12-21 17:39:14 -05:00
|
|
|
"""a helper to mock a deployed cert"""
|
2019-11-25 12:44:40 -05:00
|
|
|
g_mod = "certbot_apache._internal.configurator.ApacheConfigurator.enable_mod"
|
Distribution specific override functionality based on class inheritance (#5202)
Class inheritance based approach to distro specific overrides.
How it works:
The certbot-apache plugin entrypoint has been changed to entrypoint.ENTRYPOINT which is a variable containing appropriate override class for system, if available.
Override classes register themselves using decorator override.register() which takes a list of distribution fingerprints (ID & LIKE variables in /etc/os-release, or platform.linux_distribution() as a fallback). These end up as keys in dict override.OVERRIDE_CLASSES and values for the keys are references to the class that called the decorator, hence allowing self-registration of override classes when they are imported. The only file importing these override classes is entrypoint.py, so adding new override classes would need only one import in addition to the actual override class file.
Generic changes:
Parser initialization has been moved to separate class method, allowing easy override where needed.
Cleaned up configurator.py a bit, and moved some helper functions to newly created apache_util.py
Split Debian specific code from configurator.py to debian_override.py
Changed define_cmd to apache_cmd because the parameters are for every distribution supporting this behavior, and we're able to use the value to build the additional configuration dump commands.
Moved add_parser_mod() from configurator to parser add_mod()
Added two new configuration dump parsing methods to update_runtime_variables() in parser: update_includes() and update_modules().
Changed init_modules() in parser to accommodate the changes above. (ie. don't throw existing self.modules out).
Moved OS based constants to their respective override classes.
Refactored configurator class discovery in tests to help easier test case creation using distribution based override configurator class.
tests.util.get_apache_configurator() now takes keyword argument os_info which is string of the desired mock OS fingerprint response that's used for picking the right override class.
This PR includes two major generic additions that should vastly improve our parsing accuracy and quality:
Includes are parsed from config dump from httpd binary. This is mandatory for some distributions (Like OpenSUSE) to get visibility over the whole configuration tree because of Include statements passed on in command line, and not via root httpd.conf file.
Modules are parsed from config dump from httpd binary. This lets us jump into correct IfModule directives if for some reason we have missed the module availability (because of one being included on command line or such).
Distribution specific changes
Because of the generic changes, there are two distributions (or distribution families) that do not provide such functionality, so it had to be overridden in their respective override files. These distributions are:
CentOS, because it deliberately limits httpd binary stdout using SELinux as a feature. We are doing opportunistic config dumps here however, in case SELinux enforcing is off.
Gentoo, because it does not provide a way to invoke httpd with command line parsed from its specific configuration file. Gentoo relies heavily on Define statements that are passed over from APACHE2_OPTS variable /etc/conf.d/apache2 file and most of the configuration in root Apache configuration are dependent on these values.
Debian
Moved the Debian specific parts from configurator.py to Debian specific override.
CentOS
Parsing of /etc/sysconfig/httpd file for additional Define statements. This could hold other parameters too, but parsing everything off it would require a full Apache lexer. For CLI parameters, I think Defines are the most common ones. This is done in addition of opportunistic parsing of httpd binary config dump.
Added CentOS default Apache configuration tree for realistic test cases.
Gentoo
Parsing Defines from /etc/conf.d/apache2 variable APACHE2_OPTS, which holds additional Define statements to enable certain functionalities, enabling parts of the configuration in the Apache2 DOM. This is done instead of trying to parse httpd binary configuration dumps.
Added default Apache configuration from Gentoo to testdata, including /etc/conf.d/apache2 file for realistic test cases.
* Distribution specific override functionality based on class inheritance
* Need to patch get_systemd_os_like to as travis has proper os-release
* Added pydoc
* Move parser initialization to a method and fix Python 3 __new__ errors
* Parser changes to parse HTTPD config
* Try to get modules and includes from httpd process for better visibility over the configuration
* Had to disable duplicate-code because of test setup (PyCQA/pylint/issues/214)
* CentOS tests and linter fixes
* Gentoo override, tests and linter fixes
* Mock the process call in all the tests that require it
* Fix CentOS test mock
* Restore reseting modules list functionality for cleanup
* Move OS fingerprinting and constant mocks to parent class
* Fixes requested in review
* New entrypoint structure and started moving OS constants to override classes
* OS constants move continued, test and linter fixes
* Removed dead code
* Apache compatibility test changest to reflect OS constant restructure
* Test fix
* Requested changes
* Moved Debian specific tests to own test file
* Removed decorator based override class registration in favor of entrypoint dict
* Fix for update_includes for some versions of Augeas
* Take fedora fix into account in tests
* Review fixes
2017-12-04 14:49:18 -05:00
|
|
|
with mock.patch(g_mod):
|
2015-12-09 20:05:38 -05:00
|
|
|
config.real_deploy_cert(*args, **kwargs)
|
|
|
|
|
self.config.deploy_cert = mocked_deploy_cert
|
|
|
|
|
return self.config
|
|
|
|
|
|
2019-11-25 12:44:40 -05:00
|
|
|
@mock.patch("certbot_apache._internal.configurator.path_surgery")
|
2019-06-28 11:39:13 -04:00
|
|
|
def test_prepare_no_install(self, mock_surgery):
|
2016-07-08 16:58:39 -04:00
|
|
|
silly_path = {"PATH": "/tmp/nothingness2342"}
|
|
|
|
|
mock_surgery.return_value = False
|
|
|
|
|
with mock.patch.dict('os.environ', silly_path):
|
2023-02-16 00:02:02 -05:00
|
|
|
with pytest.raises(errors.NoInstallationError):
|
|
|
|
|
self.config.prepare()
|
|
|
|
|
assert mock_surgery.call_count == 1
|
2015-09-30 20:16:27 -04:00
|
|
|
|
2019-11-25 12:44:40 -05:00
|
|
|
@mock.patch("certbot_apache._internal.parser.ApacheParser")
|
|
|
|
|
@mock.patch("certbot_apache._internal.configurator.util.exe_exists")
|
2015-09-30 20:16:27 -04:00
|
|
|
def test_prepare_version(self, mock_exe_exists, _):
|
|
|
|
|
mock_exe_exists.return_value = True
|
2015-07-24 06:22:35 -04:00
|
|
|
self.config.version = None
|
|
|
|
|
self.config.config_test = mock.Mock()
|
|
|
|
|
self.config.get_version = mock.Mock(return_value=(1, 1))
|
|
|
|
|
|
2023-02-16 00:02:02 -05:00
|
|
|
with pytest.raises(errors.NotSupportedError):
|
|
|
|
|
self.config.prepare()
|
2015-07-24 06:22:35 -04:00
|
|
|
|
2017-05-01 17:49:12 -04:00
|
|
|
def test_prepare_locked(self):
|
2023-03-15 15:54:20 -04:00
|
|
|
# It is important to test that server_root is locked during the call to
|
|
|
|
|
# prepare (as opposed to somewhere else during plugin execution) to
|
|
|
|
|
# ensure that this lock will be acquired after the Certbot package
|
|
|
|
|
# acquires all of its locks. (Tests that Certbot calls prepare after
|
|
|
|
|
# acquiring its locks are part of the Certbot package's tests.) Not
|
|
|
|
|
# doing this could result in deadlock from two versions of Certbot that
|
|
|
|
|
# acquire its locks in a different order.
|
2017-05-01 17:49:12 -04:00
|
|
|
server_root = self.config.conf("server-root")
|
|
|
|
|
self.config.config_test = mock.Mock()
|
|
|
|
|
os.remove(os.path.join(server_root, ".certbot.lock"))
|
|
|
|
|
certbot_util.lock_and_call(self._test_prepare_locked, server_root)
|
|
|
|
|
|
2019-11-25 12:44:40 -05:00
|
|
|
@mock.patch("certbot_apache._internal.parser.ApacheParser")
|
|
|
|
|
@mock.patch("certbot_apache._internal.configurator.util.exe_exists")
|
2020-01-06 10:09:49 -05:00
|
|
|
@mock.patch("certbot_apache._internal.configurator.ApacheConfigurator.get_parsernode_root")
|
2020-01-06 10:19:33 -05:00
|
|
|
def _test_prepare_locked(self, _node, _exists, _parser):
|
2017-05-01 17:49:12 -04:00
|
|
|
try:
|
|
|
|
|
self.config.prepare()
|
|
|
|
|
except errors.PluginError as err:
|
|
|
|
|
err_msg = str(err)
|
2023-02-16 00:02:02 -05:00
|
|
|
assert "lock" in err_msg
|
|
|
|
|
assert self.config.conf("server-root") in err_msg
|
2017-05-01 17:49:12 -04:00
|
|
|
else: # pragma: no cover
|
|
|
|
|
self.fail("Exception wasn't raised!")
|
2016-07-08 03:37:52 -04:00
|
|
|
|
2015-07-24 18:47:38 -04:00
|
|
|
def test_add_parser_arguments(self): # pylint: disable=no-self-use
|
2019-11-25 12:44:40 -05:00
|
|
|
from certbot_apache._internal.configurator import ApacheConfigurator
|
2023-02-10 13:51:20 -05:00
|
|
|
|
2015-07-23 04:34:51 -04:00
|
|
|
# Weak test..
|
|
|
|
|
ApacheConfigurator.add_parser_arguments(mock.MagicMock())
|
|
|
|
|
|
2019-02-13 11:37:01 -05:00
|
|
|
def test_docs_parser_arguments(self):
|
|
|
|
|
os.environ["CERTBOT_DOCS"] = "1"
|
2019-11-25 12:44:40 -05:00
|
|
|
from certbot_apache._internal.configurator import ApacheConfigurator
|
2019-02-13 11:37:01 -05:00
|
|
|
mock_add = mock.MagicMock()
|
|
|
|
|
ApacheConfigurator.add_parser_arguments(mock_add)
|
|
|
|
|
parserargs = ["server_root", "enmod", "dismod", "le_vhost_ext",
|
|
|
|
|
"vhost_root", "logs_root", "challenge_location",
|
|
|
|
|
"handle_modules", "handle_sites", "ctl"]
|
2020-04-13 13:41:39 -04:00
|
|
|
exp = {}
|
2019-02-13 11:37:01 -05:00
|
|
|
|
2021-04-13 14:18:49 -04:00
|
|
|
for k in ApacheConfigurator.OS_DEFAULTS.__dict__.keys():
|
2019-02-13 11:37:01 -05:00
|
|
|
if k in parserargs:
|
2021-04-13 14:18:49 -04:00
|
|
|
exp[k.replace("_", "-")] = getattr(ApacheConfigurator.OS_DEFAULTS, k)
|
2019-02-13 11:37:01 -05:00
|
|
|
# Special cases
|
|
|
|
|
exp["vhost-root"] = None
|
|
|
|
|
|
|
|
|
|
found = set()
|
|
|
|
|
for call in mock_add.call_args_list:
|
|
|
|
|
found.add(call[0][0])
|
|
|
|
|
|
|
|
|
|
# Make sure that all (and only) the expected values exist
|
2023-02-16 00:02:02 -05:00
|
|
|
assert len(mock_add.call_args_list) == len(found)
|
2019-02-13 11:37:01 -05:00
|
|
|
for e in exp:
|
2022-01-03 16:05:21 -05:00
|
|
|
with self.subTest(e=e):
|
2023-02-16 00:02:02 -05:00
|
|
|
assert e in found
|
2019-02-13 11:37:01 -05:00
|
|
|
|
|
|
|
|
del os.environ["CERTBOT_DOCS"]
|
|
|
|
|
|
2018-09-06 18:00:20 -04:00
|
|
|
def test_add_parser_arguments_all_configurators(self): # pylint: disable=no-self-use
|
2019-11-25 12:44:40 -05:00
|
|
|
from certbot_apache._internal.entrypoint import OVERRIDE_CLASSES
|
2018-09-06 18:00:20 -04:00
|
|
|
for cls in OVERRIDE_CLASSES.values():
|
|
|
|
|
cls.add_parser_arguments(mock.MagicMock())
|
|
|
|
|
|
|
|
|
|
def test_all_configurators_defaults_defined(self):
|
2019-11-25 12:44:40 -05:00
|
|
|
from certbot_apache._internal.configurator import ApacheConfigurator
|
2023-02-10 13:51:20 -05:00
|
|
|
from certbot_apache._internal.entrypoint import OVERRIDE_CLASSES
|
2021-04-13 14:18:49 -04:00
|
|
|
parameters = set(ApacheConfigurator.OS_DEFAULTS.__dict__.keys())
|
2018-09-06 18:00:20 -04:00
|
|
|
for cls in OVERRIDE_CLASSES.values():
|
2023-02-16 00:02:02 -05:00
|
|
|
assert parameters.issubset(set(cls.OS_DEFAULTS.__dict__.keys())) is True
|
2018-09-06 18:00:20 -04:00
|
|
|
|
Distribution specific override functionality based on class inheritance (#5202)
Class inheritance based approach to distro specific overrides.
How it works:
The certbot-apache plugin entrypoint has been changed to entrypoint.ENTRYPOINT which is a variable containing appropriate override class for system, if available.
Override classes register themselves using decorator override.register() which takes a list of distribution fingerprints (ID & LIKE variables in /etc/os-release, or platform.linux_distribution() as a fallback). These end up as keys in dict override.OVERRIDE_CLASSES and values for the keys are references to the class that called the decorator, hence allowing self-registration of override classes when they are imported. The only file importing these override classes is entrypoint.py, so adding new override classes would need only one import in addition to the actual override class file.
Generic changes:
Parser initialization has been moved to separate class method, allowing easy override where needed.
Cleaned up configurator.py a bit, and moved some helper functions to newly created apache_util.py
Split Debian specific code from configurator.py to debian_override.py
Changed define_cmd to apache_cmd because the parameters are for every distribution supporting this behavior, and we're able to use the value to build the additional configuration dump commands.
Moved add_parser_mod() from configurator to parser add_mod()
Added two new configuration dump parsing methods to update_runtime_variables() in parser: update_includes() and update_modules().
Changed init_modules() in parser to accommodate the changes above. (ie. don't throw existing self.modules out).
Moved OS based constants to their respective override classes.
Refactored configurator class discovery in tests to help easier test case creation using distribution based override configurator class.
tests.util.get_apache_configurator() now takes keyword argument os_info which is string of the desired mock OS fingerprint response that's used for picking the right override class.
This PR includes two major generic additions that should vastly improve our parsing accuracy and quality:
Includes are parsed from config dump from httpd binary. This is mandatory for some distributions (Like OpenSUSE) to get visibility over the whole configuration tree because of Include statements passed on in command line, and not via root httpd.conf file.
Modules are parsed from config dump from httpd binary. This lets us jump into correct IfModule directives if for some reason we have missed the module availability (because of one being included on command line or such).
Distribution specific changes
Because of the generic changes, there are two distributions (or distribution families) that do not provide such functionality, so it had to be overridden in their respective override files. These distributions are:
CentOS, because it deliberately limits httpd binary stdout using SELinux as a feature. We are doing opportunistic config dumps here however, in case SELinux enforcing is off.
Gentoo, because it does not provide a way to invoke httpd with command line parsed from its specific configuration file. Gentoo relies heavily on Define statements that are passed over from APACHE2_OPTS variable /etc/conf.d/apache2 file and most of the configuration in root Apache configuration are dependent on these values.
Debian
Moved the Debian specific parts from configurator.py to Debian specific override.
CentOS
Parsing of /etc/sysconfig/httpd file for additional Define statements. This could hold other parameters too, but parsing everything off it would require a full Apache lexer. For CLI parameters, I think Defines are the most common ones. This is done in addition of opportunistic parsing of httpd binary config dump.
Added CentOS default Apache configuration tree for realistic test cases.
Gentoo
Parsing Defines from /etc/conf.d/apache2 variable APACHE2_OPTS, which holds additional Define statements to enable certain functionalities, enabling parts of the configuration in the Apache2 DOM. This is done instead of trying to parse httpd binary configuration dumps.
Added default Apache configuration from Gentoo to testdata, including /etc/conf.d/apache2 file for realistic test cases.
* Distribution specific override functionality based on class inheritance
* Need to patch get_systemd_os_like to as travis has proper os-release
* Added pydoc
* Move parser initialization to a method and fix Python 3 __new__ errors
* Parser changes to parse HTTPD config
* Try to get modules and includes from httpd process for better visibility over the configuration
* Had to disable duplicate-code because of test setup (PyCQA/pylint/issues/214)
* CentOS tests and linter fixes
* Gentoo override, tests and linter fixes
* Mock the process call in all the tests that require it
* Fix CentOS test mock
* Restore reseting modules list functionality for cleanup
* Move OS fingerprinting and constant mocks to parent class
* Fixes requested in review
* New entrypoint structure and started moving OS constants to override classes
* OS constants move continued, test and linter fixes
* Removed dead code
* Apache compatibility test changest to reflect OS constant restructure
* Test fix
* Requested changes
* Moved Debian specific tests to own test file
* Removed decorator based override class registration in favor of entrypoint dict
* Fix for update_includes for some versions of Augeas
* Take fedora fix into account in tests
* Review fixes
2017-12-04 14:49:18 -05:00
|
|
|
def test_constant(self):
|
2023-02-16 00:02:02 -05:00
|
|
|
assert "debian_apache_2_4/multiple_vhosts/apache" in self.config.options.server_root
|
Distribution specific override functionality based on class inheritance (#5202)
Class inheritance based approach to distro specific overrides.
How it works:
The certbot-apache plugin entrypoint has been changed to entrypoint.ENTRYPOINT which is a variable containing appropriate override class for system, if available.
Override classes register themselves using decorator override.register() which takes a list of distribution fingerprints (ID & LIKE variables in /etc/os-release, or platform.linux_distribution() as a fallback). These end up as keys in dict override.OVERRIDE_CLASSES and values for the keys are references to the class that called the decorator, hence allowing self-registration of override classes when they are imported. The only file importing these override classes is entrypoint.py, so adding new override classes would need only one import in addition to the actual override class file.
Generic changes:
Parser initialization has been moved to separate class method, allowing easy override where needed.
Cleaned up configurator.py a bit, and moved some helper functions to newly created apache_util.py
Split Debian specific code from configurator.py to debian_override.py
Changed define_cmd to apache_cmd because the parameters are for every distribution supporting this behavior, and we're able to use the value to build the additional configuration dump commands.
Moved add_parser_mod() from configurator to parser add_mod()
Added two new configuration dump parsing methods to update_runtime_variables() in parser: update_includes() and update_modules().
Changed init_modules() in parser to accommodate the changes above. (ie. don't throw existing self.modules out).
Moved OS based constants to their respective override classes.
Refactored configurator class discovery in tests to help easier test case creation using distribution based override configurator class.
tests.util.get_apache_configurator() now takes keyword argument os_info which is string of the desired mock OS fingerprint response that's used for picking the right override class.
This PR includes two major generic additions that should vastly improve our parsing accuracy and quality:
Includes are parsed from config dump from httpd binary. This is mandatory for some distributions (Like OpenSUSE) to get visibility over the whole configuration tree because of Include statements passed on in command line, and not via root httpd.conf file.
Modules are parsed from config dump from httpd binary. This lets us jump into correct IfModule directives if for some reason we have missed the module availability (because of one being included on command line or such).
Distribution specific changes
Because of the generic changes, there are two distributions (or distribution families) that do not provide such functionality, so it had to be overridden in their respective override files. These distributions are:
CentOS, because it deliberately limits httpd binary stdout using SELinux as a feature. We are doing opportunistic config dumps here however, in case SELinux enforcing is off.
Gentoo, because it does not provide a way to invoke httpd with command line parsed from its specific configuration file. Gentoo relies heavily on Define statements that are passed over from APACHE2_OPTS variable /etc/conf.d/apache2 file and most of the configuration in root Apache configuration are dependent on these values.
Debian
Moved the Debian specific parts from configurator.py to Debian specific override.
CentOS
Parsing of /etc/sysconfig/httpd file for additional Define statements. This could hold other parameters too, but parsing everything off it would require a full Apache lexer. For CLI parameters, I think Defines are the most common ones. This is done in addition of opportunistic parsing of httpd binary config dump.
Added CentOS default Apache configuration tree for realistic test cases.
Gentoo
Parsing Defines from /etc/conf.d/apache2 variable APACHE2_OPTS, which holds additional Define statements to enable certain functionalities, enabling parts of the configuration in the Apache2 DOM. This is done instead of trying to parse httpd binary configuration dumps.
Added default Apache configuration from Gentoo to testdata, including /etc/conf.d/apache2 file for realistic test cases.
* Distribution specific override functionality based on class inheritance
* Need to patch get_systemd_os_like to as travis has proper os-release
* Added pydoc
* Move parser initialization to a method and fix Python 3 __new__ errors
* Parser changes to parse HTTPD config
* Try to get modules and includes from httpd process for better visibility over the configuration
* Had to disable duplicate-code because of test setup (PyCQA/pylint/issues/214)
* CentOS tests and linter fixes
* Gentoo override, tests and linter fixes
* Mock the process call in all the tests that require it
* Fix CentOS test mock
* Restore reseting modules list functionality for cleanup
* Move OS fingerprinting and constant mocks to parent class
* Fixes requested in review
* New entrypoint structure and started moving OS constants to override classes
* OS constants move continued, test and linter fixes
* Removed dead code
* Apache compatibility test changest to reflect OS constant restructure
* Test fix
* Requested changes
* Moved Debian specific tests to own test file
* Removed decorator based override class registration in favor of entrypoint dict
* Fix for update_includes for some versions of Augeas
* Take fedora fix into account in tests
* Review fixes
2017-12-04 14:49:18 -05:00
|
|
|
|
2021-07-19 20:09:06 -04:00
|
|
|
@certbot_util.patch_display_util()
|
2015-11-06 03:56:50 -05:00
|
|
|
def test_get_all_names(self, mock_getutility):
|
2017-08-30 12:52:45 -04:00
|
|
|
mock_utility = mock_getutility()
|
|
|
|
|
mock_utility.notification = mock.MagicMock(return_value=True)
|
2014-12-03 07:35:49 -05:00
|
|
|
names = self.config.get_all_names()
|
2023-02-16 00:02:02 -05:00
|
|
|
assert names == {"certbot.demo", "ocspvhost.com", "encryption-example.demo",
|
2019-02-06 13:02:35 -05:00
|
|
|
"nonsym.link", "vhost.in.rootconf", "www.certbot.demo",
|
2023-02-16 00:02:02 -05:00
|
|
|
"duplicate.example.com"}
|
2014-12-03 07:35:49 -05:00
|
|
|
|
2021-07-19 20:09:06 -04:00
|
|
|
@certbot_util.patch_display_util()
|
2019-11-25 12:44:40 -05:00
|
|
|
@mock.patch("certbot_apache._internal.configurator.socket.gethostbyaddr")
|
2015-11-06 03:56:50 -05:00
|
|
|
def test_get_all_names_addrs(self, mock_gethost, mock_getutility):
|
2015-07-24 18:47:38 -04:00
|
|
|
mock_gethost.side_effect = [("google.com", "", ""), socket.error]
|
2017-08-30 12:52:45 -04:00
|
|
|
mock_utility = mock_getutility()
|
|
|
|
|
mock_utility.notification.return_value = True
|
2015-07-24 18:47:38 -04:00
|
|
|
vhost = obj.VirtualHost(
|
2015-07-24 06:22:35 -04:00
|
|
|
"fp", "ap",
|
2020-04-13 13:41:39 -04:00
|
|
|
{obj.Addr(("8.8.8.8", "443")),
|
2015-07-24 06:22:35 -04:00
|
|
|
obj.Addr(("zombo.com",)),
|
2020-04-13 13:41:39 -04:00
|
|
|
obj.Addr(("192.168.1.2"))},
|
2015-07-24 06:22:35 -04:00
|
|
|
True, False)
|
2016-05-19 19:04:18 -04:00
|
|
|
|
2015-07-24 18:47:38 -04:00
|
|
|
self.config.vhosts.append(vhost)
|
2015-07-24 06:22:35 -04:00
|
|
|
|
|
|
|
|
names = self.config.get_all_names()
|
2023-02-16 00:02:02 -05:00
|
|
|
assert len(names) == 9
|
|
|
|
|
assert "zombo.com" in names
|
|
|
|
|
assert "google.com" in names
|
|
|
|
|
assert "certbot.demo" in names
|
2015-07-24 06:22:35 -04:00
|
|
|
|
2016-08-09 17:25:35 -04:00
|
|
|
def test_get_bad_path(self):
|
2023-02-16 00:02:02 -05:00
|
|
|
assert apache_util.get_file_path(None) == None
|
|
|
|
|
assert apache_util.get_file_path("nonexistent") == None
|
|
|
|
|
assert self.config._create_vhost("nonexistent") == None # pylint: disable=protected-access
|
2016-08-09 17:25:35 -04:00
|
|
|
|
2016-09-29 22:32:22 -04:00
|
|
|
def test_get_aug_internal_path(self):
|
2019-11-25 12:44:40 -05:00
|
|
|
from certbot_apache._internal.apache_util import get_internal_aug_path
|
2016-09-29 22:32:22 -04:00
|
|
|
internal_paths = [
|
2017-09-27 18:51:28 -04:00
|
|
|
"Virtualhost", "IfModule/VirtualHost", "VirtualHost", "VirtualHost",
|
2016-09-29 22:32:22 -04:00
|
|
|
"Macro/VirtualHost", "IfModule/VirtualHost", "VirtualHost",
|
|
|
|
|
"IfModule/VirtualHost"]
|
|
|
|
|
|
|
|
|
|
for i, internal_path in enumerate(internal_paths):
|
2023-02-16 00:02:02 -05:00
|
|
|
assert get_internal_aug_path(self.vh_truth[i].path) == internal_path
|
2016-09-29 22:32:22 -04:00
|
|
|
|
2016-05-19 19:04:18 -04:00
|
|
|
def test_bad_servername_alias(self):
|
|
|
|
|
ssl_vh1 = obj.VirtualHost(
|
2020-04-13 13:41:39 -04:00
|
|
|
"fp1", "ap1", {obj.Addr(("*", "443"))},
|
2016-05-19 19:04:18 -04:00
|
|
|
True, False)
|
|
|
|
|
# pylint: disable=protected-access
|
|
|
|
|
self.config._add_servernames(ssl_vh1)
|
2023-02-16 00:02:02 -05:00
|
|
|
assert self.config._add_servername_alias("oy_vey", ssl_vh1) is None
|
2016-05-19 19:04:18 -04:00
|
|
|
|
2015-07-24 06:22:35 -04:00
|
|
|
def test_add_servernames_alias(self):
|
|
|
|
|
self.config.parser.add_dir(
|
|
|
|
|
self.vh_truth[2].path, "ServerAlias", ["*.le.co"])
|
2016-01-14 06:25:15 -05:00
|
|
|
# pylint: disable=protected-access
|
|
|
|
|
self.config._add_servernames(self.vh_truth[2])
|
2023-02-16 00:02:02 -05:00
|
|
|
assert self.vh_truth[2].get_names() == {"*.le.co", "ip-172-30-0-17"}
|
2015-07-24 06:22:35 -04:00
|
|
|
|
2014-12-03 07:35:49 -05:00
|
|
|
def test_get_virtual_hosts(self):
|
2017-09-25 15:03:09 -04:00
|
|
|
"""Make sure all vhosts are being properly found."""
|
2014-12-03 07:35:49 -05:00
|
|
|
vhs = self.config.get_virtual_hosts()
|
2023-02-16 00:02:02 -05:00
|
|
|
assert len(vhs) == 12
|
2014-12-04 07:16:22 -05:00
|
|
|
found = 0
|
2014-12-16 04:35:46 -05:00
|
|
|
|
2014-12-04 07:00:22 -05:00
|
|
|
for vhost in vhs:
|
|
|
|
|
for truth in self.vh_truth:
|
|
|
|
|
if vhost == truth:
|
2014-12-04 07:16:22 -05:00
|
|
|
found += 1
|
2014-12-04 07:00:22 -05:00
|
|
|
break
|
2015-07-19 05:22:10 -04:00
|
|
|
else:
|
2015-07-23 04:34:51 -04:00
|
|
|
raise Exception("Missed: %s" % vhost) # pragma: no cover
|
2014-12-04 07:00:22 -05:00
|
|
|
|
2023-02-16 00:02:02 -05:00
|
|
|
assert found == 12
|
2014-12-03 07:35:49 -05:00
|
|
|
|
2015-12-10 17:03:00 -05:00
|
|
|
# Handle case of non-debian layout get_virtual_hosts
|
|
|
|
|
with mock.patch(
|
2019-11-25 12:44:40 -05:00
|
|
|
"certbot_apache._internal.configurator.ApacheConfigurator.conf"
|
2016-01-10 12:15:09 -05:00
|
|
|
) as mock_conf:
|
|
|
|
|
mock_conf.return_value = False
|
2015-12-10 17:03:00 -05:00
|
|
|
vhs = self.config.get_virtual_hosts()
|
2023-02-16 00:02:02 -05:00
|
|
|
assert len(vhs) == 12
|
2015-12-10 17:03:00 -05:00
|
|
|
|
2019-11-25 12:44:40 -05:00
|
|
|
@mock.patch("certbot_apache._internal.display_ops.select_vhost")
|
2015-07-23 04:34:51 -04:00
|
|
|
def test_choose_vhost_none_avail(self, mock_select):
|
|
|
|
|
mock_select.return_value = None
|
2023-02-16 00:02:02 -05:00
|
|
|
with pytest.raises(errors.PluginError):
|
|
|
|
|
self.config.choose_vhost("none.com")
|
2015-07-23 04:34:51 -04:00
|
|
|
|
2019-11-25 12:44:40 -05:00
|
|
|
@mock.patch("certbot_apache._internal.display_ops.select_vhost")
|
2015-07-31 02:14:58 -04:00
|
|
|
def test_choose_vhost_select_vhost_ssl(self, mock_select):
|
|
|
|
|
mock_select.return_value = self.vh_truth[1]
|
2023-02-16 00:02:02 -05:00
|
|
|
assert self.vh_truth[1] == self.config.choose_vhost("none.com")
|
2015-07-31 02:14:58 -04:00
|
|
|
|
2019-11-25 12:44:40 -05:00
|
|
|
@mock.patch("certbot_apache._internal.display_ops.select_vhost")
|
|
|
|
|
@mock.patch("certbot_apache._internal.obj.VirtualHost.conflicts")
|
2017-09-25 15:03:09 -04:00
|
|
|
def test_choose_vhost_select_vhost_non_ssl(self, mock_conf, mock_select):
|
2015-07-31 02:14:58 -04:00
|
|
|
mock_select.return_value = self.vh_truth[0]
|
2017-09-25 15:03:09 -04:00
|
|
|
mock_conf.return_value = False
|
2015-07-31 02:14:58 -04:00
|
|
|
chosen_vhost = self.config.choose_vhost("none.com")
|
2016-01-29 20:11:05 -05:00
|
|
|
self.vh_truth[0].aliases.add("none.com")
|
2023-02-16 00:02:02 -05:00
|
|
|
assert self.vh_truth[0].get_names() == chosen_vhost.get_names()
|
2015-07-31 02:14:58 -04:00
|
|
|
|
|
|
|
|
# Make sure we go from HTTP -> HTTPS
|
2023-02-16 00:02:02 -05:00
|
|
|
assert self.vh_truth[0].ssl is False
|
|
|
|
|
assert chosen_vhost.ssl is True
|
2015-07-31 02:14:58 -04:00
|
|
|
|
2019-11-25 12:44:40 -05:00
|
|
|
@mock.patch("certbot_apache._internal.configurator.ApacheConfigurator._find_best_vhost")
|
|
|
|
|
@mock.patch("certbot_apache._internal.parser.ApacheParser.add_dir")
|
2017-09-25 15:03:09 -04:00
|
|
|
def test_choose_vhost_and_servername_addition(self, mock_add, mock_find):
|
|
|
|
|
ret_vh = self.vh_truth[8]
|
|
|
|
|
ret_vh.enabled = False
|
|
|
|
|
mock_find.return_value = self.vh_truth[8]
|
|
|
|
|
self.config.choose_vhost("whatever.com")
|
2023-02-16 00:02:02 -05:00
|
|
|
assert mock_add.called is True
|
2017-09-25 15:03:09 -04:00
|
|
|
|
2019-11-25 12:44:40 -05:00
|
|
|
@mock.patch("certbot_apache._internal.display_ops.select_vhost")
|
2015-12-01 19:28:15 -05:00
|
|
|
def test_choose_vhost_select_vhost_with_temp(self, mock_select):
|
|
|
|
|
mock_select.return_value = self.vh_truth[0]
|
2018-04-18 14:08:30 -04:00
|
|
|
chosen_vhost = self.config.choose_vhost("none.com", create_if_no_ssl=False)
|
2023-02-16 00:02:02 -05:00
|
|
|
assert self.vh_truth[0] == chosen_vhost
|
2015-12-01 19:28:15 -05:00
|
|
|
|
2019-11-25 12:44:40 -05:00
|
|
|
@mock.patch("certbot_apache._internal.display_ops.select_vhost")
|
2015-07-31 02:14:58 -04:00
|
|
|
def test_choose_vhost_select_vhost_conflicting_non_ssl(self, mock_select):
|
|
|
|
|
mock_select.return_value = self.vh_truth[3]
|
|
|
|
|
conflicting_vhost = obj.VirtualHost(
|
2020-04-13 13:41:39 -04:00
|
|
|
"path", "aug_path", {obj.Addr.fromstring("*:443")},
|
2016-01-14 06:25:15 -05:00
|
|
|
True, True)
|
2015-07-31 02:14:58 -04:00
|
|
|
self.config.vhosts.append(conflicting_vhost)
|
|
|
|
|
|
2023-02-16 00:02:02 -05:00
|
|
|
with pytest.raises(errors.PluginError):
|
|
|
|
|
self.config.choose_vhost("none.com")
|
2015-07-23 04:34:51 -04:00
|
|
|
|
2018-01-16 21:16:33 -05:00
|
|
|
def test_find_best_http_vhost_default(self):
|
|
|
|
|
vh = obj.VirtualHost(
|
2020-04-13 13:41:39 -04:00
|
|
|
"fp", "ap", {obj.Addr.fromstring("_default_:80")}, False, True)
|
2018-01-16 21:16:33 -05:00
|
|
|
self.config.vhosts = [vh]
|
2023-02-16 00:02:02 -05:00
|
|
|
assert self.config.find_best_http_vhost("foo.bar", False) == vh
|
2018-01-16 21:16:33 -05:00
|
|
|
|
|
|
|
|
def test_find_best_http_vhost_port(self):
|
|
|
|
|
port = "8080"
|
|
|
|
|
vh = obj.VirtualHost(
|
2020-04-13 13:41:39 -04:00
|
|
|
"fp", "ap", {obj.Addr.fromstring("*:" + port)},
|
2018-01-16 21:16:33 -05:00
|
|
|
False, True, "encryption-example.demo")
|
|
|
|
|
self.config.vhosts.append(vh)
|
2023-02-16 00:02:02 -05:00
|
|
|
assert self.config.find_best_http_vhost("foo.bar", False, port) == vh
|
2018-01-16 21:16:33 -05:00
|
|
|
|
2016-02-23 20:31:41 -05:00
|
|
|
def test_findbest_continues_on_short_domain(self):
|
|
|
|
|
# pylint: disable=protected-access
|
2023-02-16 00:02:02 -05:00
|
|
|
assert self.config._find_best_vhost("purple.com") is None
|
2016-02-23 20:31:41 -05:00
|
|
|
|
|
|
|
|
def test_findbest_continues_on_long_domain(self):
|
|
|
|
|
# pylint: disable=protected-access
|
2023-02-16 00:02:02 -05:00
|
|
|
assert self.config._find_best_vhost("green.red.purple.com") is None
|
2016-02-23 20:31:41 -05:00
|
|
|
|
2015-07-23 04:34:51 -04:00
|
|
|
def test_find_best_vhost(self):
|
2015-07-24 18:47:38 -04:00
|
|
|
# pylint: disable=protected-access
|
2023-02-16 00:02:02 -05:00
|
|
|
assert self.vh_truth[3] == self.config._find_best_vhost("certbot.demo")
|
|
|
|
|
assert self.vh_truth[0] == self.config._find_best_vhost("encryption-example.demo")
|
|
|
|
|
assert self.config._find_best_vhost("does-not-exist.com") == None
|
2015-07-23 04:34:51 -04:00
|
|
|
|
2015-07-24 06:22:35 -04:00
|
|
|
def test_find_best_vhost_variety(self):
|
2015-07-24 18:47:38 -04:00
|
|
|
# pylint: disable=protected-access
|
2015-07-24 06:22:35 -04:00
|
|
|
ssl_vh = obj.VirtualHost(
|
2020-04-13 13:41:39 -04:00
|
|
|
"fp", "ap", {obj.Addr(("*", "443")),
|
|
|
|
|
obj.Addr(("zombo.com",))},
|
2015-07-24 06:22:35 -04:00
|
|
|
True, False)
|
|
|
|
|
self.config.vhosts.append(ssl_vh)
|
2023-02-16 00:02:02 -05:00
|
|
|
assert self.config._find_best_vhost("zombo.com") == ssl_vh
|
2015-07-24 06:22:35 -04:00
|
|
|
|
2015-07-23 04:34:51 -04:00
|
|
|
def test_find_best_vhost_default(self):
|
2015-07-24 18:47:38 -04:00
|
|
|
# pylint: disable=protected-access
|
2015-07-23 04:34:51 -04:00
|
|
|
# Assume only the two default vhosts.
|
2015-07-24 18:47:38 -04:00
|
|
|
self.config.vhosts = [
|
|
|
|
|
vh for vh in self.config.vhosts
|
2017-09-25 15:03:09 -04:00
|
|
|
if vh.name not in ["certbot.demo", "nonsym.link",
|
2019-02-06 13:02:35 -05:00
|
|
|
"encryption-example.demo", "duplicate.example.com",
|
2017-09-25 15:03:09 -04:00
|
|
|
"ocspvhost.com", "vhost.in.rootconf"]
|
2016-02-23 20:31:41 -05:00
|
|
|
and "*.blue.purple.com" not in vh.aliases
|
2015-07-24 18:47:38 -04:00
|
|
|
]
|
2023-02-16 00:02:02 -05:00
|
|
|
assert self.config._find_best_vhost("encryption-example.demo") == \
|
|
|
|
|
self.vh_truth[2]
|
2015-07-23 04:34:51 -04:00
|
|
|
|
|
|
|
|
def test_non_default_vhosts(self):
|
|
|
|
|
# pylint: disable=protected-access
|
2018-01-15 23:47:03 -05:00
|
|
|
vhosts = self.config._non_default_vhosts(self.config.vhosts)
|
2023-02-16 00:02:02 -05:00
|
|
|
assert len(vhosts) == 10
|
2014-12-03 07:35:49 -05:00
|
|
|
|
Command-line UX overhaul (#8852)
Streamline and reorganize Certbot's CLI output.
This change is a substantial command-line UX overhaul,
based on previous user research. The main goal was to streamline
and clarify output. To see more verbose output, use the -v or -vv flags.
---
* nginx,apache: CLI logging changes
- Add "Successfully deployed ..." message using display_util
- Remove IReporter usage and replace with display_util
- Standardize "... could not find a VirtualHost ..." error
This changes also bumps the version of certbot required by certbot-nginx
and certbot-apache to take use of the new display_util function.
* fix certbot_compatibility_test
since the http plugins now require IDisplay, we need to inject it
* fix dependency version on certbot
* use better asserts
* try fix oldest deps
because certbot 1.10.0 depends on acme>=1.8.0, we need to use
acme==1.8.0 in the -oldest tests
* cli: redesign output of new certificate reporting
Changes the output of run, certonly and certonly --csr. No longer uses
IReporter.
* cli: redesign output of failed authz reporting
* fix problem sorting to be stable between py2 & 3
* add some catch-all error text
* cli: dont use IReporter for EFF donation prompt
* add per-authenticator hints
* pass achalls to auth_hint, write some tests
* exclude static auth hints from coverage
* dont call auth_hint unless derived from .Plugin
* dns fallback hint: dont assume --dns-blah works
--dns-blah won't work for third-party plugins, they need to be specified
using --authenticator dns-blah.
* add code comments about the auth_hint interface
* renew: don't restart the installer for dry-runs
Prevents Certbot from superfluously invoking the installer restart
during dry-run renewals. (This does not affect authenticator restarts).
Additionally removes some CLI output that was reporting the fullchain
path of the renewed certificate.
* update CHANGELOG.md
* cli: redesign output when cert installation failed
- Display a message when certificate installation begins.
- Don't use IReporter, just log errors immediately if restart/rollback
fails.
- Prompt the user with a command to retry the installation process once
they have fixed any underlying problems.
* vary by preconfigured_renewal
and move expiry date to be above the renewal advice
* update code comment
Co-authored-by: ohemorange <ebportnoy@gmail.com>
* update code comment
Co-authored-by: ohemorange <ebportnoy@gmail.com>
* fix lint
* derve cert name from cert_path, if possible
* fix type annotation
* text change in nginx hint
Co-authored-by: ohemorange <ebportnoy@gmail.com>
* print message when restarting server after renewal
* log: print "advice" when exiting with an error
When running in non-quiet mode.
* try fix -oldest lock_test.py
* fix docstring
* s/Restarting/Reloading/ when notifying the user
* fix test name
Co-authored-by: ohemorange <ebportnoy@gmail.com>
* type annotations
* s/using the {} plugin/installer: {}/
* copy: avoid "plugin" where possible
* link to user guide#automated-renewals
when not running with --preconfigured-renewal
* cli: reduce default logging verbosity
* fix lock_test: -vv is needed to see logger.debug
* Change comment in log.py to match the change to default verbosity
* Audit and adjust logging levels in apache module
* Audit and adjust logging levels in nginx module
* Audit, adjust logging levels, and improve logging calls in certbot module
* Fix tests to mock correct methods and classes
* typo in non-preconfigured-renewal message
Co-authored-by: ohemorange <ebportnoy@gmail.com>
* fix test
* revert acme version bump
* catch up to python3 changes
* Revert "revert acme version bump"
This reverts commit fa83d6a51cf8d0e7e17da53c6b751ad12945d0cf.
* Change ocsp check error to warning since it's non-fatal
* Update storage_test in parallel with last change
* get rid of leading newline on "Deploying [...]"
* shrink renewal and installation success messages
* print logfile rather than logdir in exit handler
* Decrease logging level to info for idempotent operation where enhancement is already set
* Display cert not yet due for renewal message when renewing and no other action will be taken, and change cert to certificate
* also write to logger so it goes in the log file
* Don't double write to log file; fix main test
* cli: remove trailing newline on new cert reporting
* ignore type error
* revert accidental changes to dependencies
* Pass tests in any timezone by using utcfromtimestamp
* Add changelog entry
* fix nits
* Improve wording of try again message
* minor wording change to changelog
* hooks: send hook stdout to CLI stdout
includes both --manual and --{pre,post,renew} hooks
* update docstrings and remove TODO
* add a pending deprecation on execute_command
* add test coverage for both
* update deprecation text
Co-authored-by: ohemorange <ebportnoy@gmail.com>
Co-authored-by: Alex Zorin <alex@zorin.id.au>
Co-authored-by: alexzorin <alex@zor.io>
2021-05-24 20:47:39 -04:00
|
|
|
@mock.patch('certbot_apache._internal.configurator.display_util.notify')
|
|
|
|
|
def test_deploy_cert_enable_new_vhost(self, unused_mock_notify):
|
2017-09-25 15:03:09 -04:00
|
|
|
# Create
|
|
|
|
|
ssl_vhost = self.config.make_vhost_ssl(self.vh_truth[0])
|
2020-03-23 19:49:52 -04:00
|
|
|
self.config.parser.modules["ssl_module"] = None
|
|
|
|
|
self.config.parser.modules["mod_ssl.c"] = None
|
|
|
|
|
self.config.parser.modules["socache_shmcb_module"] = None
|
Distribution specific override functionality based on class inheritance (#5202)
Class inheritance based approach to distro specific overrides.
How it works:
The certbot-apache plugin entrypoint has been changed to entrypoint.ENTRYPOINT which is a variable containing appropriate override class for system, if available.
Override classes register themselves using decorator override.register() which takes a list of distribution fingerprints (ID & LIKE variables in /etc/os-release, or platform.linux_distribution() as a fallback). These end up as keys in dict override.OVERRIDE_CLASSES and values for the keys are references to the class that called the decorator, hence allowing self-registration of override classes when they are imported. The only file importing these override classes is entrypoint.py, so adding new override classes would need only one import in addition to the actual override class file.
Generic changes:
Parser initialization has been moved to separate class method, allowing easy override where needed.
Cleaned up configurator.py a bit, and moved some helper functions to newly created apache_util.py
Split Debian specific code from configurator.py to debian_override.py
Changed define_cmd to apache_cmd because the parameters are for every distribution supporting this behavior, and we're able to use the value to build the additional configuration dump commands.
Moved add_parser_mod() from configurator to parser add_mod()
Added two new configuration dump parsing methods to update_runtime_variables() in parser: update_includes() and update_modules().
Changed init_modules() in parser to accommodate the changes above. (ie. don't throw existing self.modules out).
Moved OS based constants to their respective override classes.
Refactored configurator class discovery in tests to help easier test case creation using distribution based override configurator class.
tests.util.get_apache_configurator() now takes keyword argument os_info which is string of the desired mock OS fingerprint response that's used for picking the right override class.
This PR includes two major generic additions that should vastly improve our parsing accuracy and quality:
Includes are parsed from config dump from httpd binary. This is mandatory for some distributions (Like OpenSUSE) to get visibility over the whole configuration tree because of Include statements passed on in command line, and not via root httpd.conf file.
Modules are parsed from config dump from httpd binary. This lets us jump into correct IfModule directives if for some reason we have missed the module availability (because of one being included on command line or such).
Distribution specific changes
Because of the generic changes, there are two distributions (or distribution families) that do not provide such functionality, so it had to be overridden in their respective override files. These distributions are:
CentOS, because it deliberately limits httpd binary stdout using SELinux as a feature. We are doing opportunistic config dumps here however, in case SELinux enforcing is off.
Gentoo, because it does not provide a way to invoke httpd with command line parsed from its specific configuration file. Gentoo relies heavily on Define statements that are passed over from APACHE2_OPTS variable /etc/conf.d/apache2 file and most of the configuration in root Apache configuration are dependent on these values.
Debian
Moved the Debian specific parts from configurator.py to Debian specific override.
CentOS
Parsing of /etc/sysconfig/httpd file for additional Define statements. This could hold other parameters too, but parsing everything off it would require a full Apache lexer. For CLI parameters, I think Defines are the most common ones. This is done in addition of opportunistic parsing of httpd binary config dump.
Added CentOS default Apache configuration tree for realistic test cases.
Gentoo
Parsing Defines from /etc/conf.d/apache2 variable APACHE2_OPTS, which holds additional Define statements to enable certain functionalities, enabling parts of the configuration in the Apache2 DOM. This is done instead of trying to parse httpd binary configuration dumps.
Added default Apache configuration from Gentoo to testdata, including /etc/conf.d/apache2 file for realistic test cases.
* Distribution specific override functionality based on class inheritance
* Need to patch get_systemd_os_like to as travis has proper os-release
* Added pydoc
* Move parser initialization to a method and fix Python 3 __new__ errors
* Parser changes to parse HTTPD config
* Try to get modules and includes from httpd process for better visibility over the configuration
* Had to disable duplicate-code because of test setup (PyCQA/pylint/issues/214)
* CentOS tests and linter fixes
* Gentoo override, tests and linter fixes
* Mock the process call in all the tests that require it
* Fix CentOS test mock
* Restore reseting modules list functionality for cleanup
* Move OS fingerprinting and constant mocks to parent class
* Fixes requested in review
* New entrypoint structure and started moving OS constants to override classes
* OS constants move continued, test and linter fixes
* Removed dead code
* Apache compatibility test changest to reflect OS constant restructure
* Test fix
* Requested changes
* Moved Debian specific tests to own test file
* Removed decorator based override class registration in favor of entrypoint dict
* Fix for update_includes for some versions of Augeas
* Take fedora fix into account in tests
* Review fixes
2017-12-04 14:49:18 -05:00
|
|
|
|
2023-02-16 00:02:02 -05:00
|
|
|
assert ssl_vhost.enabled is False
|
2017-09-25 15:03:09 -04:00
|
|
|
self.config.deploy_cert(
|
|
|
|
|
"encryption-example.demo", "example/cert.pem", "example/key.pem",
|
|
|
|
|
"example/cert_chain.pem", "example/fullchain.pem")
|
2023-02-16 00:02:02 -05:00
|
|
|
assert ssl_vhost.enabled is True
|
2017-09-25 15:03:09 -04:00
|
|
|
|
2018-02-14 11:16:20 -05:00
|
|
|
def test_no_duplicate_include(self):
|
|
|
|
|
def mock_find_dir(directive, argument, _):
|
|
|
|
|
"""Mock method for parser.find_dir"""
|
|
|
|
|
if directive == "Include" and argument.endswith("options-ssl-apache.conf"):
|
|
|
|
|
return ["/path/to/whatever"]
|
2018-05-14 12:33:30 -04:00
|
|
|
return None # pragma: no cover
|
2018-02-14 11:16:20 -05:00
|
|
|
|
|
|
|
|
mock_add = mock.MagicMock()
|
|
|
|
|
self.config.parser.add_dir = mock_add
|
|
|
|
|
self.config._add_dummy_ssl_directives(self.vh_truth[0]) # pylint: disable=protected-access
|
|
|
|
|
tried_to_add = False
|
|
|
|
|
for a in mock_add.call_args_list:
|
|
|
|
|
if a[0][1] == "Include" and a[0][2] == self.config.mod_ssl_conf:
|
|
|
|
|
tried_to_add = True
|
|
|
|
|
# Include should be added, find_dir is not patched, and returns falsy
|
2023-02-16 00:02:02 -05:00
|
|
|
assert tried_to_add is True
|
2018-02-14 11:16:20 -05:00
|
|
|
|
|
|
|
|
self.config.parser.find_dir = mock_find_dir
|
|
|
|
|
mock_add.reset_mock()
|
|
|
|
|
self.config._add_dummy_ssl_directives(self.vh_truth[0]) # pylint: disable=protected-access
|
|
|
|
|
for a in mock_add.call_args_list:
|
2018-05-15 13:40:32 -04:00
|
|
|
if a[0][1] == "Include" and a[0][2] == self.config.mod_ssl_conf:
|
|
|
|
|
self.fail("Include shouldn't be added, as patched find_dir 'finds' existing one") \
|
|
|
|
|
# pragma: no cover
|
2018-02-14 11:16:20 -05:00
|
|
|
|
Command-line UX overhaul (#8852)
Streamline and reorganize Certbot's CLI output.
This change is a substantial command-line UX overhaul,
based on previous user research. The main goal was to streamline
and clarify output. To see more verbose output, use the -v or -vv flags.
---
* nginx,apache: CLI logging changes
- Add "Successfully deployed ..." message using display_util
- Remove IReporter usage and replace with display_util
- Standardize "... could not find a VirtualHost ..." error
This changes also bumps the version of certbot required by certbot-nginx
and certbot-apache to take use of the new display_util function.
* fix certbot_compatibility_test
since the http plugins now require IDisplay, we need to inject it
* fix dependency version on certbot
* use better asserts
* try fix oldest deps
because certbot 1.10.0 depends on acme>=1.8.0, we need to use
acme==1.8.0 in the -oldest tests
* cli: redesign output of new certificate reporting
Changes the output of run, certonly and certonly --csr. No longer uses
IReporter.
* cli: redesign output of failed authz reporting
* fix problem sorting to be stable between py2 & 3
* add some catch-all error text
* cli: dont use IReporter for EFF donation prompt
* add per-authenticator hints
* pass achalls to auth_hint, write some tests
* exclude static auth hints from coverage
* dont call auth_hint unless derived from .Plugin
* dns fallback hint: dont assume --dns-blah works
--dns-blah won't work for third-party plugins, they need to be specified
using --authenticator dns-blah.
* add code comments about the auth_hint interface
* renew: don't restart the installer for dry-runs
Prevents Certbot from superfluously invoking the installer restart
during dry-run renewals. (This does not affect authenticator restarts).
Additionally removes some CLI output that was reporting the fullchain
path of the renewed certificate.
* update CHANGELOG.md
* cli: redesign output when cert installation failed
- Display a message when certificate installation begins.
- Don't use IReporter, just log errors immediately if restart/rollback
fails.
- Prompt the user with a command to retry the installation process once
they have fixed any underlying problems.
* vary by preconfigured_renewal
and move expiry date to be above the renewal advice
* update code comment
Co-authored-by: ohemorange <ebportnoy@gmail.com>
* update code comment
Co-authored-by: ohemorange <ebportnoy@gmail.com>
* fix lint
* derve cert name from cert_path, if possible
* fix type annotation
* text change in nginx hint
Co-authored-by: ohemorange <ebportnoy@gmail.com>
* print message when restarting server after renewal
* log: print "advice" when exiting with an error
When running in non-quiet mode.
* try fix -oldest lock_test.py
* fix docstring
* s/Restarting/Reloading/ when notifying the user
* fix test name
Co-authored-by: ohemorange <ebportnoy@gmail.com>
* type annotations
* s/using the {} plugin/installer: {}/
* copy: avoid "plugin" where possible
* link to user guide#automated-renewals
when not running with --preconfigured-renewal
* cli: reduce default logging verbosity
* fix lock_test: -vv is needed to see logger.debug
* Change comment in log.py to match the change to default verbosity
* Audit and adjust logging levels in apache module
* Audit and adjust logging levels in nginx module
* Audit, adjust logging levels, and improve logging calls in certbot module
* Fix tests to mock correct methods and classes
* typo in non-preconfigured-renewal message
Co-authored-by: ohemorange <ebportnoy@gmail.com>
* fix test
* revert acme version bump
* catch up to python3 changes
* Revert "revert acme version bump"
This reverts commit fa83d6a51cf8d0e7e17da53c6b751ad12945d0cf.
* Change ocsp check error to warning since it's non-fatal
* Update storage_test in parallel with last change
* get rid of leading newline on "Deploying [...]"
* shrink renewal and installation success messages
* print logfile rather than logdir in exit handler
* Decrease logging level to info for idempotent operation where enhancement is already set
* Display cert not yet due for renewal message when renewing and no other action will be taken, and change cert to certificate
* also write to logger so it goes in the log file
* Don't double write to log file; fix main test
* cli: remove trailing newline on new cert reporting
* ignore type error
* revert accidental changes to dependencies
* Pass tests in any timezone by using utcfromtimestamp
* Add changelog entry
* fix nits
* Improve wording of try again message
* minor wording change to changelog
* hooks: send hook stdout to CLI stdout
includes both --manual and --{pre,post,renew} hooks
* update docstrings and remove TODO
* add a pending deprecation on execute_command
* add test coverage for both
* update deprecation text
Co-authored-by: ohemorange <ebportnoy@gmail.com>
Co-authored-by: Alex Zorin <alex@zorin.id.au>
Co-authored-by: alexzorin <alex@zor.io>
2021-05-24 20:47:39 -04:00
|
|
|
@mock.patch('certbot_apache._internal.configurator.display_util.notify')
|
|
|
|
|
def test_deploy_cert(self, unused_mock_notify):
|
2020-03-23 19:49:52 -04:00
|
|
|
self.config.parser.modules["ssl_module"] = None
|
|
|
|
|
self.config.parser.modules["mod_ssl.c"] = None
|
|
|
|
|
self.config.parser.modules["socache_shmcb_module"] = None
|
2017-09-25 15:03:09 -04:00
|
|
|
# Patch _add_dummy_ssl_directives to make sure we write them correctly
|
|
|
|
|
# pylint: disable=protected-access
|
|
|
|
|
orig_add_dummy = self.config._add_dummy_ssl_directives
|
|
|
|
|
def mock_add_dummy_ssl(vhostpath):
|
|
|
|
|
"""Mock method for _add_dummy_ssl_directives"""
|
|
|
|
|
def find_args(path, directive):
|
|
|
|
|
"""Return list of arguments in requested directive at path"""
|
|
|
|
|
f_args = []
|
|
|
|
|
dirs = self.config.parser.find_dir(directive, None,
|
|
|
|
|
path)
|
|
|
|
|
for d in dirs:
|
|
|
|
|
f_args.append(self.config.parser.get_arg(d))
|
|
|
|
|
return f_args
|
|
|
|
|
# Verify that the dummy directives do not exist
|
2023-02-16 00:02:02 -05:00
|
|
|
assert "insert_cert_file_path" not in find_args(vhostpath, "SSLCertificateFile")
|
|
|
|
|
assert "insert_key_file_path" not in find_args(vhostpath, "SSLCertificateKeyFile")
|
2017-09-25 15:03:09 -04:00
|
|
|
orig_add_dummy(vhostpath)
|
|
|
|
|
# Verify that the dummy directives exist
|
2023-02-16 00:02:02 -05:00
|
|
|
assert "insert_cert_file_path" in find_args(vhostpath, "SSLCertificateFile")
|
|
|
|
|
assert "insert_key_file_path" in find_args(vhostpath, "SSLCertificateKeyFile")
|
2017-09-25 15:03:09 -04:00
|
|
|
# pylint: disable=protected-access
|
|
|
|
|
self.config._add_dummy_ssl_directives = mock_add_dummy_ssl
|
|
|
|
|
|
2015-01-15 04:43:54 -05:00
|
|
|
# Get the default 443 vhost
|
|
|
|
|
self.config.assoc["random.demo"] = self.vh_truth[1]
|
2014-12-05 20:31:36 -05:00
|
|
|
self.config.deploy_cert(
|
2015-01-15 04:43:54 -05:00
|
|
|
"random.demo",
|
2014-12-05 20:31:36 -05:00
|
|
|
"example/cert.pem", "example/key.pem", "example/cert_chain.pem")
|
2015-01-15 04:43:54 -05:00
|
|
|
self.config.save()
|
2014-12-05 20:31:36 -05:00
|
|
|
|
2015-07-19 05:22:10 -04:00
|
|
|
# Verify ssl_module was enabled.
|
2023-02-16 00:02:02 -05:00
|
|
|
assert self.vh_truth[1].enabled is True
|
|
|
|
|
assert "ssl_module" in self.config.parser.modules
|
2015-07-19 05:22:10 -04:00
|
|
|
|
2014-12-17 00:00:14 -05:00
|
|
|
loc_cert = self.config.parser.find_dir(
|
2015-07-19 05:22:10 -04:00
|
|
|
"sslcertificatefile", "example/cert.pem", self.vh_truth[1].path)
|
2014-12-17 00:00:14 -05:00
|
|
|
loc_key = self.config.parser.find_dir(
|
2015-07-19 05:22:10 -04:00
|
|
|
"sslcertificateKeyfile", "example/key.pem", self.vh_truth[1].path)
|
2014-12-17 00:00:14 -05:00
|
|
|
loc_chain = self.config.parser.find_dir(
|
2015-07-19 05:22:10 -04:00
|
|
|
"SSLCertificateChainFile", "example/cert_chain.pem",
|
|
|
|
|
self.vh_truth[1].path)
|
2014-12-05 20:31:36 -05:00
|
|
|
|
|
|
|
|
# Verify one directive was found in the correct file
|
2023-02-16 00:02:02 -05:00
|
|
|
assert len(loc_cert) == 1
|
|
|
|
|
assert apache_util.get_file_path(loc_cert[0]) == \
|
|
|
|
|
self.vh_truth[1].filep
|
2014-12-05 20:31:36 -05:00
|
|
|
|
2023-02-16 00:02:02 -05:00
|
|
|
assert len(loc_key) == 1
|
|
|
|
|
assert apache_util.get_file_path(loc_key[0]) == \
|
|
|
|
|
self.vh_truth[1].filep
|
2014-12-05 20:31:36 -05:00
|
|
|
|
2023-02-16 00:02:02 -05:00
|
|
|
assert len(loc_chain) == 1
|
|
|
|
|
assert apache_util.get_file_path(loc_chain[0]) == \
|
|
|
|
|
self.vh_truth[1].filep
|
2014-12-03 07:35:49 -05:00
|
|
|
|
2015-07-23 04:34:51 -04:00
|
|
|
# One more time for chain directive setting
|
|
|
|
|
self.config.deploy_cert(
|
|
|
|
|
"random.demo",
|
|
|
|
|
"two/cert.pem", "two/key.pem", "two/cert_chain.pem")
|
2023-02-16 00:02:02 -05:00
|
|
|
assert self.config.parser.find_dir(
|
2015-07-23 04:34:51 -04:00
|
|
|
"SSLCertificateChainFile", "two/cert_chain.pem",
|
2023-02-16 00:02:02 -05:00
|
|
|
self.vh_truth[1].path)
|
2015-07-23 04:34:51 -04:00
|
|
|
|
2018-01-11 07:46:48 -05:00
|
|
|
def test_add_listen_80(self):
|
|
|
|
|
mock_find = mock.Mock()
|
|
|
|
|
mock_add_dir = mock.Mock()
|
|
|
|
|
mock_find.return_value = []
|
|
|
|
|
self.config.parser.find_dir = mock_find
|
|
|
|
|
self.config.parser.add_dir = mock_add_dir
|
|
|
|
|
self.config.ensure_listen("80")
|
2023-02-16 00:02:02 -05:00
|
|
|
assert mock_add_dir.called is True
|
|
|
|
|
assert mock_find.called is True
|
|
|
|
|
assert mock_add_dir.call_args[0][1] == "Listen"
|
|
|
|
|
assert mock_add_dir.call_args[0][2] == "80"
|
2018-01-11 07:46:48 -05:00
|
|
|
|
|
|
|
|
def test_add_listen_80_named(self):
|
|
|
|
|
mock_find = mock.Mock()
|
|
|
|
|
mock_find.return_value = ["test1", "test2", "test3"]
|
|
|
|
|
mock_get = mock.Mock()
|
|
|
|
|
mock_get.side_effect = ["1.2.3.4:80", "[::1]:80", "1.1.1.1:443"]
|
|
|
|
|
mock_add_dir = mock.Mock()
|
|
|
|
|
|
|
|
|
|
self.config.parser.find_dir = mock_find
|
|
|
|
|
self.config.parser.get_arg = mock_get
|
|
|
|
|
self.config.parser.add_dir = mock_add_dir
|
|
|
|
|
|
|
|
|
|
self.config.ensure_listen("80")
|
2023-02-16 00:02:02 -05:00
|
|
|
assert mock_add_dir.call_count == 0
|
2018-01-11 07:46:48 -05:00
|
|
|
|
|
|
|
|
# Reset return lists and inputs
|
|
|
|
|
mock_add_dir.reset_mock()
|
|
|
|
|
mock_get.side_effect = ["1.2.3.4:80", "[::1]:80", "1.1.1.1:443"]
|
|
|
|
|
|
|
|
|
|
# Test
|
|
|
|
|
self.config.ensure_listen("8080")
|
2023-02-16 00:02:02 -05:00
|
|
|
assert mock_add_dir.call_count == 3
|
|
|
|
|
assert mock_add_dir.called is True
|
|
|
|
|
assert mock_add_dir.call_args[0][1] == "Listen"
|
2018-02-12 19:43:59 -05:00
|
|
|
call_found = False
|
|
|
|
|
for mock_call in mock_add_dir.mock_calls:
|
|
|
|
|
if mock_call[1][2] == ['1.2.3.4:8080']:
|
|
|
|
|
call_found = True
|
2023-02-16 00:02:02 -05:00
|
|
|
assert call_found is True
|
2018-01-11 07:46:48 -05:00
|
|
|
|
2020-03-23 19:49:52 -04:00
|
|
|
@mock.patch("certbot_apache._internal.parser.ApacheParser.reset_modules")
|
|
|
|
|
def test_prepare_server_https(self, mock_reset):
|
2015-08-17 14:07:54 -04:00
|
|
|
mock_enable = mock.Mock()
|
|
|
|
|
self.config.enable_mod = mock_enable
|
|
|
|
|
|
2015-07-19 19:48:27 -04:00
|
|
|
mock_find = mock.Mock()
|
|
|
|
|
mock_add_dir = mock.Mock()
|
|
|
|
|
mock_find.return_value = []
|
|
|
|
|
|
|
|
|
|
# This will test the Add listen
|
|
|
|
|
self.config.parser.find_dir = mock_find
|
|
|
|
|
self.config.parser.add_dir_to_ifmodssl = mock_add_dir
|
|
|
|
|
self.config.prepare_server_https("443")
|
2016-02-01 21:21:02 -05:00
|
|
|
# Changing the order these modules are enabled breaks the reverter
|
2023-02-16 00:02:02 -05:00
|
|
|
assert mock_enable.call_args_list[0][0][0] == "socache_shmcb"
|
|
|
|
|
assert mock_enable.call_args[0][0] == "ssl"
|
|
|
|
|
assert mock_enable.call_args[1] == {"temp": False}
|
2015-08-17 14:07:54 -04:00
|
|
|
|
2015-08-17 16:11:48 -04:00
|
|
|
self.config.prepare_server_https("8080", temp=True)
|
2016-02-01 21:21:02 -05:00
|
|
|
# Changing the order these modules are enabled breaks the reverter
|
2023-02-16 00:02:02 -05:00
|
|
|
assert mock_enable.call_args_list[2][0][0] == "socache_shmcb"
|
|
|
|
|
assert mock_enable.call_args[0][0] == "ssl"
|
2015-08-17 14:07:54 -04:00
|
|
|
# Enable mod is temporary
|
2023-02-16 00:02:02 -05:00
|
|
|
assert mock_enable.call_args[1] == {"temp": True}
|
2015-08-17 14:07:54 -04:00
|
|
|
|
2023-02-16 00:02:02 -05:00
|
|
|
assert mock_add_dir.call_count == 2
|
2015-07-19 19:48:27 -04:00
|
|
|
|
2020-03-23 19:49:52 -04:00
|
|
|
@mock.patch("certbot_apache._internal.parser.ApacheParser.reset_modules")
|
|
|
|
|
def test_prepare_server_https_named_listen(self, mock_reset):
|
2015-12-08 08:22:52 -05:00
|
|
|
mock_find = mock.Mock()
|
|
|
|
|
mock_find.return_value = ["test1", "test2", "test3"]
|
|
|
|
|
mock_get = mock.Mock()
|
|
|
|
|
mock_get.side_effect = ["1.2.3.4:80", "[::1]:80", "1.1.1.1:443"]
|
|
|
|
|
mock_add_dir = mock.Mock()
|
|
|
|
|
mock_enable = mock.Mock()
|
|
|
|
|
|
|
|
|
|
self.config.parser.find_dir = mock_find
|
|
|
|
|
self.config.parser.get_arg = mock_get
|
|
|
|
|
self.config.parser.add_dir_to_ifmodssl = mock_add_dir
|
|
|
|
|
self.config.enable_mod = mock_enable
|
|
|
|
|
|
|
|
|
|
# Test Listen statements with specific ip listeed
|
|
|
|
|
self.config.prepare_server_https("443")
|
2016-06-20 01:57:51 -04:00
|
|
|
# Should be 0 as one interface already listens to 443
|
2023-02-16 00:02:02 -05:00
|
|
|
assert mock_add_dir.call_count == 0
|
2015-12-08 08:22:52 -05:00
|
|
|
|
|
|
|
|
# Reset return lists and inputs
|
|
|
|
|
mock_add_dir.reset_mock()
|
|
|
|
|
mock_get.side_effect = ["1.2.3.4:80", "[::1]:80", "1.1.1.1:443"]
|
|
|
|
|
|
|
|
|
|
# Test
|
|
|
|
|
self.config.prepare_server_https("8080", temp=True)
|
2023-02-16 00:02:02 -05:00
|
|
|
assert mock_add_dir.call_count == 3
|
2017-02-24 21:21:21 -05:00
|
|
|
call_args_list = [mock_add_dir.call_args_list[i][0][2] for i in range(3)]
|
2023-02-16 00:02:02 -05:00
|
|
|
assert sorted(call_args_list) == \
|
2017-02-24 21:21:21 -05:00
|
|
|
sorted([["1.2.3.4:8080", "https"],
|
|
|
|
|
["[::1]:8080", "https"],
|
2023-02-16 00:02:02 -05:00
|
|
|
["1.1.1.1:8080", "https"]])
|
2015-12-08 08:22:52 -05:00
|
|
|
|
2016-06-20 01:57:51 -04:00
|
|
|
# mock_get.side_effect = ["1.2.3.4:80", "[::1]:80"]
|
|
|
|
|
# mock_find.return_value = ["test1", "test2", "test3"]
|
|
|
|
|
# self.config.parser.get_arg = mock_get
|
|
|
|
|
# self.config.prepare_server_https("8080", temp=True)
|
|
|
|
|
# self.assertEqual(self.listens, 0)
|
|
|
|
|
|
2020-03-23 19:49:52 -04:00
|
|
|
@mock.patch("certbot_apache._internal.parser.ApacheParser.reset_modules")
|
|
|
|
|
def test_prepare_server_https_needed_listen(self, mock_reset):
|
2016-06-20 01:57:51 -04:00
|
|
|
mock_find = mock.Mock()
|
|
|
|
|
mock_find.return_value = ["test1", "test2"]
|
|
|
|
|
mock_get = mock.Mock()
|
|
|
|
|
mock_get.side_effect = ["1.2.3.4:8080", "80"]
|
|
|
|
|
mock_add_dir = mock.Mock()
|
|
|
|
|
mock_enable = mock.Mock()
|
|
|
|
|
|
|
|
|
|
self.config.parser.find_dir = mock_find
|
|
|
|
|
self.config.parser.get_arg = mock_get
|
|
|
|
|
self.config.parser.add_dir_to_ifmodssl = mock_add_dir
|
|
|
|
|
self.config.enable_mod = mock_enable
|
|
|
|
|
|
|
|
|
|
self.config.prepare_server_https("443")
|
2023-02-16 00:02:02 -05:00
|
|
|
assert mock_add_dir.call_count == 1
|
2016-06-20 01:57:51 -04:00
|
|
|
|
2020-03-23 19:49:52 -04:00
|
|
|
@mock.patch("certbot_apache._internal.parser.ApacheParser.reset_modules")
|
|
|
|
|
def test_prepare_server_https_mixed_listen(self, mock_reset):
|
2016-01-05 11:51:34 -05:00
|
|
|
mock_find = mock.Mock()
|
|
|
|
|
mock_find.return_value = ["test1", "test2"]
|
|
|
|
|
mock_get = mock.Mock()
|
|
|
|
|
mock_get.side_effect = ["1.2.3.4:8080", "443"]
|
|
|
|
|
mock_add_dir = mock.Mock()
|
|
|
|
|
mock_enable = mock.Mock()
|
|
|
|
|
|
|
|
|
|
self.config.parser.find_dir = mock_find
|
|
|
|
|
self.config.parser.get_arg = mock_get
|
|
|
|
|
self.config.parser.add_dir_to_ifmodssl = mock_add_dir
|
|
|
|
|
self.config.enable_mod = mock_enable
|
|
|
|
|
|
|
|
|
|
# Test Listen statements with specific ip listeed
|
|
|
|
|
self.config.prepare_server_https("443")
|
2016-01-14 06:25:15 -05:00
|
|
|
# Should only be 2 here, as the third interface
|
|
|
|
|
# already listens to the correct port
|
2023-02-16 00:02:02 -05:00
|
|
|
assert mock_add_dir.call_count == 0
|
2016-01-05 11:51:34 -05:00
|
|
|
|
2017-05-15 15:22:47 -04:00
|
|
|
def test_make_vhost_ssl_with_mock_span(self):
|
|
|
|
|
# span excludes the closing </VirtualHost> tag in older versions
|
|
|
|
|
# of Augeas
|
|
|
|
|
return_value = [self.vh_truth[0].filep, 1, 12, 0, 0, 0, 1142]
|
2019-06-28 11:39:13 -04:00
|
|
|
with mock.patch.object(self.config.parser.aug, 'span') as mock_span:
|
2017-05-15 15:22:47 -04:00
|
|
|
mock_span.return_value = return_value
|
|
|
|
|
self.test_make_vhost_ssl()
|
|
|
|
|
|
|
|
|
|
def test_make_vhost_ssl_with_mock_span2(self):
|
|
|
|
|
# span includes the closing </VirtualHost> tag in newer versions
|
|
|
|
|
# of Augeas
|
|
|
|
|
return_value = [self.vh_truth[0].filep, 1, 12, 0, 0, 0, 1157]
|
2019-06-28 11:39:13 -04:00
|
|
|
with mock.patch.object(self.config.parser.aug, 'span') as mock_span:
|
2017-05-15 15:22:47 -04:00
|
|
|
mock_span.return_value = return_value
|
|
|
|
|
self.test_make_vhost_ssl()
|
2016-09-28 14:34:27 -04:00
|
|
|
|
2017-09-25 15:03:09 -04:00
|
|
|
def test_make_vhost_ssl_nonsymlink(self):
|
|
|
|
|
ssl_vhost_slink = self.config.make_vhost_ssl(self.vh_truth[8])
|
2023-02-16 00:02:02 -05:00
|
|
|
assert ssl_vhost_slink.ssl is True
|
|
|
|
|
assert ssl_vhost_slink.enabled is True
|
|
|
|
|
assert ssl_vhost_slink.name == "nonsym.link"
|
2017-09-25 15:03:09 -04:00
|
|
|
|
|
|
|
|
def test_make_vhost_ssl_nonexistent_vhost_path(self):
|
2018-08-02 11:17:38 -04:00
|
|
|
ssl_vhost = self.config.make_vhost_ssl(self.vh_truth[1])
|
2023-02-16 00:02:02 -05:00
|
|
|
assert os.path.dirname(ssl_vhost.filep) == \
|
|
|
|
|
os.path.dirname(filesystem.realpath(self.vh_truth[1].filep))
|
2017-09-25 15:03:09 -04:00
|
|
|
|
2014-12-06 05:33:06 -05:00
|
|
|
def test_make_vhost_ssl(self):
|
|
|
|
|
ssl_vhost = self.config.make_vhost_ssl(self.vh_truth[0])
|
|
|
|
|
|
2023-02-16 00:02:02 -05:00
|
|
|
assert ssl_vhost.filep == \
|
2014-12-06 05:33:06 -05:00
|
|
|
os.path.join(self.config_path, "sites-available",
|
2023-02-16 00:02:02 -05:00
|
|
|
"encryption-example-le-ssl.conf")
|
2014-12-06 05:33:06 -05:00
|
|
|
|
2023-02-16 00:02:02 -05:00
|
|
|
assert ssl_vhost.path == \
|
|
|
|
|
"/files" + ssl_vhost.filep + "/IfModule/Virtualhost"
|
|
|
|
|
assert len(ssl_vhost.addrs) == 1
|
|
|
|
|
assert {obj.Addr.fromstring("*:443")} == ssl_vhost.addrs
|
|
|
|
|
assert ssl_vhost.name == "encryption-example.demo"
|
|
|
|
|
assert ssl_vhost.ssl is True
|
|
|
|
|
assert ssl_vhost.enabled is False
|
2014-12-06 05:33:06 -05:00
|
|
|
|
2023-02-16 00:02:02 -05:00
|
|
|
assert len(self.config.vhosts) == 13
|
2014-12-06 05:33:06 -05:00
|
|
|
|
2015-11-20 17:31:01 -05:00
|
|
|
def test_clean_vhost_ssl(self):
|
|
|
|
|
# pylint: disable=protected-access
|
|
|
|
|
for directive in ["SSLCertificateFile", "SSLCertificateKeyFile",
|
|
|
|
|
"SSLCertificateChainFile", "SSLCACertificatePath"]:
|
|
|
|
|
for _ in range(10):
|
2016-01-14 06:25:15 -05:00
|
|
|
self.config.parser.add_dir(self.vh_truth[1].path,
|
|
|
|
|
directive, ["bogus"])
|
2015-11-20 17:31:01 -05:00
|
|
|
self.config.save()
|
|
|
|
|
|
|
|
|
|
self.config._clean_vhost(self.vh_truth[1])
|
|
|
|
|
self.config.save()
|
|
|
|
|
|
|
|
|
|
loc_cert = self.config.parser.find_dir(
|
|
|
|
|
'SSLCertificateFile', None, self.vh_truth[1].path, False)
|
|
|
|
|
loc_key = self.config.parser.find_dir(
|
|
|
|
|
'SSLCertificateKeyFile', None, self.vh_truth[1].path, False)
|
|
|
|
|
loc_chain = self.config.parser.find_dir(
|
|
|
|
|
'SSLCertificateChainFile', None, self.vh_truth[1].path, False)
|
|
|
|
|
loc_cacert = self.config.parser.find_dir(
|
|
|
|
|
'SSLCACertificatePath', None, self.vh_truth[1].path, False)
|
|
|
|
|
|
2023-02-16 00:02:02 -05:00
|
|
|
assert len(loc_cert) == 1
|
|
|
|
|
assert len(loc_key) == 1
|
2015-11-20 17:31:01 -05:00
|
|
|
|
2023-02-16 00:02:02 -05:00
|
|
|
assert len(loc_chain) == 0
|
2015-11-20 17:31:01 -05:00
|
|
|
|
2023-02-16 00:02:02 -05:00
|
|
|
assert len(loc_cacert) == 10
|
2015-11-20 17:31:01 -05:00
|
|
|
|
2015-11-16 00:00:42 -05:00
|
|
|
def test_deduplicate_directives(self):
|
2015-11-10 16:54:54 -05:00
|
|
|
# pylint: disable=protected-access
|
2015-11-16 00:00:42 -05:00
|
|
|
DIRECTIVE = "Foo"
|
|
|
|
|
for _ in range(10):
|
2016-01-14 06:25:15 -05:00
|
|
|
self.config.parser.add_dir(self.vh_truth[1].path,
|
|
|
|
|
DIRECTIVE, ["bar"])
|
2015-11-10 16:54:54 -05:00
|
|
|
self.config.save()
|
2015-11-13 16:49:59 -05:00
|
|
|
|
2015-11-16 00:00:42 -05:00
|
|
|
self.config._deduplicate_directives(self.vh_truth[1].path, [DIRECTIVE])
|
2015-11-10 16:54:54 -05:00
|
|
|
self.config.save()
|
|
|
|
|
|
2023-02-16 00:02:02 -05:00
|
|
|
assert len(self.config.parser.find_dir(
|
|
|
|
|
DIRECTIVE, None, self.vh_truth[1].path, False)) == 1
|
2015-11-10 16:54:54 -05:00
|
|
|
|
2015-11-16 00:00:42 -05:00
|
|
|
def test_remove_directives(self):
|
2015-11-13 16:49:59 -05:00
|
|
|
# pylint: disable=protected-access
|
2015-11-16 00:00:42 -05:00
|
|
|
DIRECTIVES = ["Foo", "Bar"]
|
|
|
|
|
for directive in DIRECTIVES:
|
|
|
|
|
for _ in range(10):
|
2017-09-25 15:03:09 -04:00
|
|
|
self.config.parser.add_dir(self.vh_truth[2].path,
|
2016-01-14 06:25:15 -05:00
|
|
|
directive, ["baz"])
|
2015-11-13 16:49:59 -05:00
|
|
|
self.config.save()
|
|
|
|
|
|
2017-09-25 15:03:09 -04:00
|
|
|
self.config._remove_directives(self.vh_truth[2].path, DIRECTIVES)
|
2015-11-13 16:49:59 -05:00
|
|
|
self.config.save()
|
|
|
|
|
|
2015-11-16 00:00:42 -05:00
|
|
|
for directive in DIRECTIVES:
|
2023-02-16 00:02:02 -05:00
|
|
|
assert len(self.config.parser.find_dir(
|
|
|
|
|
directive, None, self.vh_truth[2].path, False)) == 0
|
2015-11-13 16:49:59 -05:00
|
|
|
|
2015-07-24 06:22:35 -04:00
|
|
|
def test_make_vhost_ssl_bad_write(self):
|
|
|
|
|
mock_open = mock.mock_open()
|
|
|
|
|
# This calls open
|
|
|
|
|
self.config.reverter.register_file_creation = mock.Mock()
|
|
|
|
|
mock_open.side_effect = IOError
|
2021-02-09 14:43:15 -05:00
|
|
|
with mock.patch("builtins.open", mock_open):
|
2023-02-16 00:02:02 -05:00
|
|
|
with pytest.raises(errors.PluginError):
|
|
|
|
|
self.config.make_vhost_ssl(self.vh_truth[0])
|
2015-07-24 06:22:35 -04:00
|
|
|
|
|
|
|
|
def test_get_ssl_vhost_path(self):
|
2015-07-24 18:47:38 -04:00
|
|
|
# pylint: disable=protected-access
|
2023-02-16 00:02:02 -05:00
|
|
|
assert self.config._get_ssl_vhost_path("example_path").endswith(".conf") is True
|
2015-07-24 06:22:35 -04:00
|
|
|
|
2019-11-25 12:44:40 -05:00
|
|
|
@mock.patch("certbot_apache._internal.configurator.http_01.ApacheHttp01.perform")
|
|
|
|
|
@mock.patch("certbot_apache._internal.configurator.ApacheConfigurator.restart")
|
2019-03-15 19:39:43 -04:00
|
|
|
def test_perform(self, mock_restart, mock_http_perform):
|
2015-01-06 04:57:07 -05:00
|
|
|
# Only tests functionality specific to configurator.perform
|
|
|
|
|
# Note: As more challenges are offered this will have to be expanded
|
2018-01-10 23:14:56 -05:00
|
|
|
account_key, achalls = self.get_key_and_achalls()
|
|
|
|
|
|
2019-03-15 19:39:43 -04:00
|
|
|
expected = [achall.response(account_key) for achall in achalls]
|
|
|
|
|
mock_http_perform.return_value = expected
|
2015-01-06 04:57:07 -05:00
|
|
|
|
2018-01-10 23:14:56 -05:00
|
|
|
responses = self.config.perform(achalls)
|
2015-01-06 04:57:07 -05:00
|
|
|
|
2023-02-16 00:02:02 -05:00
|
|
|
assert mock_http_perform.call_count == 1
|
|
|
|
|
assert responses == expected
|
2015-01-06 04:57:07 -05:00
|
|
|
|
2023-02-16 00:02:02 -05:00
|
|
|
assert mock_restart.call_count == 1
|
2015-01-09 08:30:15 -05:00
|
|
|
|
2019-11-25 12:44:40 -05:00
|
|
|
@mock.patch("certbot_apache._internal.configurator.ApacheConfigurator.restart")
|
2020-01-06 10:19:33 -05:00
|
|
|
@mock.patch("certbot_apache._internal.apache_util._get_runtime_cfg")
|
Distribution specific override functionality based on class inheritance (#5202)
Class inheritance based approach to distro specific overrides.
How it works:
The certbot-apache plugin entrypoint has been changed to entrypoint.ENTRYPOINT which is a variable containing appropriate override class for system, if available.
Override classes register themselves using decorator override.register() which takes a list of distribution fingerprints (ID & LIKE variables in /etc/os-release, or platform.linux_distribution() as a fallback). These end up as keys in dict override.OVERRIDE_CLASSES and values for the keys are references to the class that called the decorator, hence allowing self-registration of override classes when they are imported. The only file importing these override classes is entrypoint.py, so adding new override classes would need only one import in addition to the actual override class file.
Generic changes:
Parser initialization has been moved to separate class method, allowing easy override where needed.
Cleaned up configurator.py a bit, and moved some helper functions to newly created apache_util.py
Split Debian specific code from configurator.py to debian_override.py
Changed define_cmd to apache_cmd because the parameters are for every distribution supporting this behavior, and we're able to use the value to build the additional configuration dump commands.
Moved add_parser_mod() from configurator to parser add_mod()
Added two new configuration dump parsing methods to update_runtime_variables() in parser: update_includes() and update_modules().
Changed init_modules() in parser to accommodate the changes above. (ie. don't throw existing self.modules out).
Moved OS based constants to their respective override classes.
Refactored configurator class discovery in tests to help easier test case creation using distribution based override configurator class.
tests.util.get_apache_configurator() now takes keyword argument os_info which is string of the desired mock OS fingerprint response that's used for picking the right override class.
This PR includes two major generic additions that should vastly improve our parsing accuracy and quality:
Includes are parsed from config dump from httpd binary. This is mandatory for some distributions (Like OpenSUSE) to get visibility over the whole configuration tree because of Include statements passed on in command line, and not via root httpd.conf file.
Modules are parsed from config dump from httpd binary. This lets us jump into correct IfModule directives if for some reason we have missed the module availability (because of one being included on command line or such).
Distribution specific changes
Because of the generic changes, there are two distributions (or distribution families) that do not provide such functionality, so it had to be overridden in their respective override files. These distributions are:
CentOS, because it deliberately limits httpd binary stdout using SELinux as a feature. We are doing opportunistic config dumps here however, in case SELinux enforcing is off.
Gentoo, because it does not provide a way to invoke httpd with command line parsed from its specific configuration file. Gentoo relies heavily on Define statements that are passed over from APACHE2_OPTS variable /etc/conf.d/apache2 file and most of the configuration in root Apache configuration are dependent on these values.
Debian
Moved the Debian specific parts from configurator.py to Debian specific override.
CentOS
Parsing of /etc/sysconfig/httpd file for additional Define statements. This could hold other parameters too, but parsing everything off it would require a full Apache lexer. For CLI parameters, I think Defines are the most common ones. This is done in addition of opportunistic parsing of httpd binary config dump.
Added CentOS default Apache configuration tree for realistic test cases.
Gentoo
Parsing Defines from /etc/conf.d/apache2 variable APACHE2_OPTS, which holds additional Define statements to enable certain functionalities, enabling parts of the configuration in the Apache2 DOM. This is done instead of trying to parse httpd binary configuration dumps.
Added default Apache configuration from Gentoo to testdata, including /etc/conf.d/apache2 file for realistic test cases.
* Distribution specific override functionality based on class inheritance
* Need to patch get_systemd_os_like to as travis has proper os-release
* Added pydoc
* Move parser initialization to a method and fix Python 3 __new__ errors
* Parser changes to parse HTTPD config
* Try to get modules and includes from httpd process for better visibility over the configuration
* Had to disable duplicate-code because of test setup (PyCQA/pylint/issues/214)
* CentOS tests and linter fixes
* Gentoo override, tests and linter fixes
* Mock the process call in all the tests that require it
* Fix CentOS test mock
* Restore reseting modules list functionality for cleanup
* Move OS fingerprinting and constant mocks to parent class
* Fixes requested in review
* New entrypoint structure and started moving OS constants to override classes
* OS constants move continued, test and linter fixes
* Removed dead code
* Apache compatibility test changest to reflect OS constant restructure
* Test fix
* Requested changes
* Moved Debian specific tests to own test file
* Removed decorator based override class registration in favor of entrypoint dict
* Fix for update_includes for some versions of Augeas
* Take fedora fix into account in tests
* Review fixes
2017-12-04 14:49:18 -05:00
|
|
|
def test_cleanup(self, mock_cfg, mock_restart):
|
|
|
|
|
mock_cfg.return_value = ""
|
2018-01-10 23:14:56 -05:00
|
|
|
_, achalls = self.get_key_and_achalls()
|
2015-07-24 06:22:35 -04:00
|
|
|
|
2018-01-10 23:14:56 -05:00
|
|
|
for achall in achalls:
|
|
|
|
|
self.config._chall_out.add(achall) # pylint: disable=protected-access
|
2015-07-24 06:22:35 -04:00
|
|
|
|
2018-01-10 23:14:56 -05:00
|
|
|
for i, achall in enumerate(achalls):
|
|
|
|
|
self.config.cleanup([achall])
|
|
|
|
|
if i == len(achalls) - 1:
|
2023-02-16 00:02:02 -05:00
|
|
|
assert mock_restart.called is True
|
2018-01-10 23:14:56 -05:00
|
|
|
else:
|
2023-02-16 00:02:02 -05:00
|
|
|
assert mock_restart.called is False
|
2015-07-24 06:22:35 -04:00
|
|
|
|
2019-11-25 12:44:40 -05:00
|
|
|
@mock.patch("certbot_apache._internal.configurator.ApacheConfigurator.restart")
|
2020-01-06 10:19:33 -05:00
|
|
|
@mock.patch("certbot_apache._internal.apache_util._get_runtime_cfg")
|
Distribution specific override functionality based on class inheritance (#5202)
Class inheritance based approach to distro specific overrides.
How it works:
The certbot-apache plugin entrypoint has been changed to entrypoint.ENTRYPOINT which is a variable containing appropriate override class for system, if available.
Override classes register themselves using decorator override.register() which takes a list of distribution fingerprints (ID & LIKE variables in /etc/os-release, or platform.linux_distribution() as a fallback). These end up as keys in dict override.OVERRIDE_CLASSES and values for the keys are references to the class that called the decorator, hence allowing self-registration of override classes when they are imported. The only file importing these override classes is entrypoint.py, so adding new override classes would need only one import in addition to the actual override class file.
Generic changes:
Parser initialization has been moved to separate class method, allowing easy override where needed.
Cleaned up configurator.py a bit, and moved some helper functions to newly created apache_util.py
Split Debian specific code from configurator.py to debian_override.py
Changed define_cmd to apache_cmd because the parameters are for every distribution supporting this behavior, and we're able to use the value to build the additional configuration dump commands.
Moved add_parser_mod() from configurator to parser add_mod()
Added two new configuration dump parsing methods to update_runtime_variables() in parser: update_includes() and update_modules().
Changed init_modules() in parser to accommodate the changes above. (ie. don't throw existing self.modules out).
Moved OS based constants to their respective override classes.
Refactored configurator class discovery in tests to help easier test case creation using distribution based override configurator class.
tests.util.get_apache_configurator() now takes keyword argument os_info which is string of the desired mock OS fingerprint response that's used for picking the right override class.
This PR includes two major generic additions that should vastly improve our parsing accuracy and quality:
Includes are parsed from config dump from httpd binary. This is mandatory for some distributions (Like OpenSUSE) to get visibility over the whole configuration tree because of Include statements passed on in command line, and not via root httpd.conf file.
Modules are parsed from config dump from httpd binary. This lets us jump into correct IfModule directives if for some reason we have missed the module availability (because of one being included on command line or such).
Distribution specific changes
Because of the generic changes, there are two distributions (or distribution families) that do not provide such functionality, so it had to be overridden in their respective override files. These distributions are:
CentOS, because it deliberately limits httpd binary stdout using SELinux as a feature. We are doing opportunistic config dumps here however, in case SELinux enforcing is off.
Gentoo, because it does not provide a way to invoke httpd with command line parsed from its specific configuration file. Gentoo relies heavily on Define statements that are passed over from APACHE2_OPTS variable /etc/conf.d/apache2 file and most of the configuration in root Apache configuration are dependent on these values.
Debian
Moved the Debian specific parts from configurator.py to Debian specific override.
CentOS
Parsing of /etc/sysconfig/httpd file for additional Define statements. This could hold other parameters too, but parsing everything off it would require a full Apache lexer. For CLI parameters, I think Defines are the most common ones. This is done in addition of opportunistic parsing of httpd binary config dump.
Added CentOS default Apache configuration tree for realistic test cases.
Gentoo
Parsing Defines from /etc/conf.d/apache2 variable APACHE2_OPTS, which holds additional Define statements to enable certain functionalities, enabling parts of the configuration in the Apache2 DOM. This is done instead of trying to parse httpd binary configuration dumps.
Added default Apache configuration from Gentoo to testdata, including /etc/conf.d/apache2 file for realistic test cases.
* Distribution specific override functionality based on class inheritance
* Need to patch get_systemd_os_like to as travis has proper os-release
* Added pydoc
* Move parser initialization to a method and fix Python 3 __new__ errors
* Parser changes to parse HTTPD config
* Try to get modules and includes from httpd process for better visibility over the configuration
* Had to disable duplicate-code because of test setup (PyCQA/pylint/issues/214)
* CentOS tests and linter fixes
* Gentoo override, tests and linter fixes
* Mock the process call in all the tests that require it
* Fix CentOS test mock
* Restore reseting modules list functionality for cleanup
* Move OS fingerprinting and constant mocks to parent class
* Fixes requested in review
* New entrypoint structure and started moving OS constants to override classes
* OS constants move continued, test and linter fixes
* Removed dead code
* Apache compatibility test changest to reflect OS constant restructure
* Test fix
* Requested changes
* Moved Debian specific tests to own test file
* Removed decorator based override class registration in favor of entrypoint dict
* Fix for update_includes for some versions of Augeas
* Take fedora fix into account in tests
* Review fixes
2017-12-04 14:49:18 -05:00
|
|
|
def test_cleanup_no_errors(self, mock_cfg, mock_restart):
|
|
|
|
|
mock_cfg.return_value = ""
|
2018-01-10 23:14:56 -05:00
|
|
|
_, achalls = self.get_key_and_achalls()
|
|
|
|
|
self.config.http_doer = mock.MagicMock()
|
2015-07-24 06:22:35 -04:00
|
|
|
|
2018-01-10 23:14:56 -05:00
|
|
|
for achall in achalls:
|
|
|
|
|
self.config._chall_out.add(achall) # pylint: disable=protected-access
|
2015-07-24 06:22:35 -04:00
|
|
|
|
2018-01-10 23:14:56 -05:00
|
|
|
self.config.cleanup([achalls[-1]])
|
2023-02-16 00:02:02 -05:00
|
|
|
assert mock_restart.called is False
|
2015-07-24 06:22:35 -04:00
|
|
|
|
2018-01-10 23:14:56 -05:00
|
|
|
self.config.cleanup(achalls)
|
2023-02-16 00:02:02 -05:00
|
|
|
assert mock_restart.called is True
|
2015-07-24 06:22:35 -04:00
|
|
|
|
2016-05-26 14:43:00 -04:00
|
|
|
@mock.patch("certbot.util.run_script")
|
2015-07-30 02:40:07 -04:00
|
|
|
def test_get_version(self, mock_script):
|
|
|
|
|
mock_script.return_value = (
|
2015-02-09 03:12:43 -05:00
|
|
|
"Server Version: Apache/2.4.2 (Debian)", "")
|
2023-02-16 00:02:02 -05:00
|
|
|
assert self.config.get_version() == (2, 4, 2)
|
2015-02-09 03:12:43 -05:00
|
|
|
|
2015-07-30 02:40:07 -04:00
|
|
|
mock_script.return_value = (
|
2015-02-09 03:12:43 -05:00
|
|
|
"Server Version: Apache/2 (Linux)", "")
|
2023-02-16 00:02:02 -05:00
|
|
|
assert self.config.get_version() == (2,)
|
2015-02-09 03:12:43 -05:00
|
|
|
|
2015-07-30 02:40:07 -04:00
|
|
|
mock_script.return_value = (
|
2015-02-09 03:12:43 -05:00
|
|
|
"Server Version: Apache (Debian)", "")
|
2023-02-16 00:02:02 -05:00
|
|
|
with pytest.raises(errors.PluginError):
|
|
|
|
|
self.config.get_version()
|
2015-02-09 03:12:43 -05:00
|
|
|
|
2015-07-30 02:40:07 -04:00
|
|
|
mock_script.return_value = (
|
2016-01-14 06:25:15 -05:00
|
|
|
"Server Version: Apache/2.3{0} Apache/2.4.7".format(
|
|
|
|
|
os.linesep), "")
|
2023-02-16 00:02:02 -05:00
|
|
|
with pytest.raises(errors.PluginError):
|
|
|
|
|
self.config.get_version()
|
2015-02-09 03:12:43 -05:00
|
|
|
|
2015-07-30 02:40:07 -04:00
|
|
|
mock_script.side_effect = errors.SubprocessError("Can't find program")
|
2023-02-16 00:02:02 -05:00
|
|
|
with pytest.raises(errors.PluginError):
|
|
|
|
|
self.config.get_version()
|
2015-02-10 03:55:40 -05:00
|
|
|
|
2019-11-25 12:44:40 -05:00
|
|
|
@mock.patch("certbot_apache._internal.configurator.util.run_script")
|
2015-11-30 22:13:50 -05:00
|
|
|
def test_restart(self, _):
|
2015-07-24 06:22:35 -04:00
|
|
|
self.config.restart()
|
|
|
|
|
|
2019-11-25 12:44:40 -05:00
|
|
|
@mock.patch("certbot_apache._internal.configurator.util.run_script")
|
2015-11-30 22:13:50 -05:00
|
|
|
def test_restart_bad_process(self, mock_run_script):
|
|
|
|
|
mock_run_script.side_effect = [None, errors.SubprocessError]
|
2015-07-24 06:22:35 -04:00
|
|
|
|
2023-02-16 00:02:02 -05:00
|
|
|
with pytest.raises(errors.MisconfigurationError):
|
|
|
|
|
self.config.restart()
|
2015-07-24 06:22:35 -04:00
|
|
|
|
2016-05-26 14:43:00 -04:00
|
|
|
@mock.patch("certbot.util.run_script")
|
2015-07-30 02:40:07 -04:00
|
|
|
def test_config_test(self, _):
|
2015-07-24 06:22:35 -04:00
|
|
|
self.config.config_test()
|
|
|
|
|
|
2016-05-26 14:43:00 -04:00
|
|
|
@mock.patch("certbot.util.run_script")
|
2015-07-30 02:40:07 -04:00
|
|
|
def test_config_test_bad_process(self, mock_run_script):
|
|
|
|
|
mock_run_script.side_effect = errors.SubprocessError
|
2015-07-24 06:22:35 -04:00
|
|
|
|
2023-02-16 00:02:02 -05:00
|
|
|
with pytest.raises(errors.MisconfigurationError):
|
|
|
|
|
self.config.config_test()
|
2015-07-24 06:22:35 -04:00
|
|
|
|
|
|
|
|
def test_more_info(self):
|
2023-02-16 00:02:02 -05:00
|
|
|
assert self.config.more_info()
|
2015-07-24 06:22:35 -04:00
|
|
|
|
|
|
|
|
def test_get_chall_pref(self):
|
2023-02-16 00:02:02 -05:00
|
|
|
assert isinstance(self.config.get_chall_pref(""), list)
|
2015-07-24 06:22:35 -04:00
|
|
|
|
2015-11-07 06:01:33 -05:00
|
|
|
def test_install_ssl_options_conf(self):
|
2015-07-24 06:22:35 -04:00
|
|
|
path = os.path.join(self.work_dir, "test_it")
|
2017-05-23 19:25:39 -04:00
|
|
|
other_path = os.path.join(self.work_dir, "other_test_it")
|
Distribution specific override functionality based on class inheritance (#5202)
Class inheritance based approach to distro specific overrides.
How it works:
The certbot-apache plugin entrypoint has been changed to entrypoint.ENTRYPOINT which is a variable containing appropriate override class for system, if available.
Override classes register themselves using decorator override.register() which takes a list of distribution fingerprints (ID & LIKE variables in /etc/os-release, or platform.linux_distribution() as a fallback). These end up as keys in dict override.OVERRIDE_CLASSES and values for the keys are references to the class that called the decorator, hence allowing self-registration of override classes when they are imported. The only file importing these override classes is entrypoint.py, so adding new override classes would need only one import in addition to the actual override class file.
Generic changes:
Parser initialization has been moved to separate class method, allowing easy override where needed.
Cleaned up configurator.py a bit, and moved some helper functions to newly created apache_util.py
Split Debian specific code from configurator.py to debian_override.py
Changed define_cmd to apache_cmd because the parameters are for every distribution supporting this behavior, and we're able to use the value to build the additional configuration dump commands.
Moved add_parser_mod() from configurator to parser add_mod()
Added two new configuration dump parsing methods to update_runtime_variables() in parser: update_includes() and update_modules().
Changed init_modules() in parser to accommodate the changes above. (ie. don't throw existing self.modules out).
Moved OS based constants to their respective override classes.
Refactored configurator class discovery in tests to help easier test case creation using distribution based override configurator class.
tests.util.get_apache_configurator() now takes keyword argument os_info which is string of the desired mock OS fingerprint response that's used for picking the right override class.
This PR includes two major generic additions that should vastly improve our parsing accuracy and quality:
Includes are parsed from config dump from httpd binary. This is mandatory for some distributions (Like OpenSUSE) to get visibility over the whole configuration tree because of Include statements passed on in command line, and not via root httpd.conf file.
Modules are parsed from config dump from httpd binary. This lets us jump into correct IfModule directives if for some reason we have missed the module availability (because of one being included on command line or such).
Distribution specific changes
Because of the generic changes, there are two distributions (or distribution families) that do not provide such functionality, so it had to be overridden in their respective override files. These distributions are:
CentOS, because it deliberately limits httpd binary stdout using SELinux as a feature. We are doing opportunistic config dumps here however, in case SELinux enforcing is off.
Gentoo, because it does not provide a way to invoke httpd with command line parsed from its specific configuration file. Gentoo relies heavily on Define statements that are passed over from APACHE2_OPTS variable /etc/conf.d/apache2 file and most of the configuration in root Apache configuration are dependent on these values.
Debian
Moved the Debian specific parts from configurator.py to Debian specific override.
CentOS
Parsing of /etc/sysconfig/httpd file for additional Define statements. This could hold other parameters too, but parsing everything off it would require a full Apache lexer. For CLI parameters, I think Defines are the most common ones. This is done in addition of opportunistic parsing of httpd binary config dump.
Added CentOS default Apache configuration tree for realistic test cases.
Gentoo
Parsing Defines from /etc/conf.d/apache2 variable APACHE2_OPTS, which holds additional Define statements to enable certain functionalities, enabling parts of the configuration in the Apache2 DOM. This is done instead of trying to parse httpd binary configuration dumps.
Added default Apache configuration from Gentoo to testdata, including /etc/conf.d/apache2 file for realistic test cases.
* Distribution specific override functionality based on class inheritance
* Need to patch get_systemd_os_like to as travis has proper os-release
* Added pydoc
* Move parser initialization to a method and fix Python 3 __new__ errors
* Parser changes to parse HTTPD config
* Try to get modules and includes from httpd process for better visibility over the configuration
* Had to disable duplicate-code because of test setup (PyCQA/pylint/issues/214)
* CentOS tests and linter fixes
* Gentoo override, tests and linter fixes
* Mock the process call in all the tests that require it
* Fix CentOS test mock
* Restore reseting modules list functionality for cleanup
* Move OS fingerprinting and constant mocks to parent class
* Fixes requested in review
* New entrypoint structure and started moving OS constants to override classes
* OS constants move continued, test and linter fixes
* Removed dead code
* Apache compatibility test changest to reflect OS constant restructure
* Test fix
* Requested changes
* Moved Debian specific tests to own test file
* Removed decorator based override class registration in favor of entrypoint dict
* Fix for update_includes for some versions of Augeas
* Take fedora fix into account in tests
* Review fixes
2017-12-04 14:49:18 -05:00
|
|
|
self.config.install_ssl_options_conf(path, other_path)
|
2023-02-16 00:02:02 -05:00
|
|
|
assert os.path.isfile(path) is True
|
|
|
|
|
assert os.path.isfile(other_path) is True
|
2015-07-24 06:22:35 -04:00
|
|
|
|
2015-07-22 05:05:01 -04:00
|
|
|
# TEST ENHANCEMENTS
|
2015-07-24 06:22:35 -04:00
|
|
|
def test_supported_enhancements(self):
|
2023-02-16 00:02:02 -05:00
|
|
|
assert isinstance(self.config.supported_enhancements(), list)
|
2015-07-24 06:22:35 -04:00
|
|
|
|
2016-09-28 14:34:27 -04:00
|
|
|
def test_find_http_vhost_without_ancestor(self):
|
|
|
|
|
# pylint: disable=protected-access
|
|
|
|
|
vhost = self.vh_truth[0]
|
|
|
|
|
vhost.ssl = True
|
|
|
|
|
vhost.ancestor = None
|
|
|
|
|
res = self.config._get_http_vhost(vhost)
|
2023-02-16 00:02:02 -05:00
|
|
|
assert self.vh_truth[0].name == res.name
|
|
|
|
|
assert self.vh_truth[0].aliases == res.aliases
|
2016-09-28 14:34:27 -04:00
|
|
|
|
2019-11-25 12:44:40 -05:00
|
|
|
@mock.patch("certbot_apache._internal.configurator.ApacheConfigurator._get_http_vhost")
|
|
|
|
|
@mock.patch("certbot_apache._internal.display_ops.select_vhost")
|
2016-05-26 14:43:00 -04:00
|
|
|
@mock.patch("certbot.util.exe_exists")
|
2016-05-19 19:04:18 -04:00
|
|
|
def test_enhance_unknown_vhost(self, mock_exe, mock_sel_vhost, mock_get):
|
2020-03-23 19:49:52 -04:00
|
|
|
self.config.parser.modules["rewrite_module"] = None
|
2015-12-02 20:40:12 -05:00
|
|
|
mock_exe.return_value = True
|
2016-05-19 19:04:18 -04:00
|
|
|
ssl_vh1 = obj.VirtualHost(
|
2020-04-13 13:41:39 -04:00
|
|
|
"fp1", "ap1", {obj.Addr(("*", "443"))},
|
2015-12-02 20:40:12 -05:00
|
|
|
True, False)
|
2016-05-19 19:04:18 -04:00
|
|
|
ssl_vh1.name = "satoshi.com"
|
|
|
|
|
self.config.vhosts.append(ssl_vh1)
|
|
|
|
|
mock_sel_vhost.return_value = None
|
|
|
|
|
mock_get.return_value = None
|
|
|
|
|
|
2023-02-16 00:02:02 -05:00
|
|
|
with pytest.raises(errors.PluginError):
|
|
|
|
|
self.config.enhance("satoshi.com", "redirect")
|
2015-12-02 20:40:12 -05:00
|
|
|
|
2015-07-22 05:05:01 -04:00
|
|
|
def test_enhance_unknown_enhancement(self):
|
2023-02-16 00:02:02 -05:00
|
|
|
with pytest.raises(errors.PluginError):
|
|
|
|
|
self.config.enhance("certbot.demo", "unknown_enhancement")
|
2015-07-22 05:05:01 -04:00
|
|
|
|
2018-04-18 14:08:30 -04:00
|
|
|
def test_enhance_no_ssl_vhost(self):
|
Command-line UX overhaul (#8852)
Streamline and reorganize Certbot's CLI output.
This change is a substantial command-line UX overhaul,
based on previous user research. The main goal was to streamline
and clarify output. To see more verbose output, use the -v or -vv flags.
---
* nginx,apache: CLI logging changes
- Add "Successfully deployed ..." message using display_util
- Remove IReporter usage and replace with display_util
- Standardize "... could not find a VirtualHost ..." error
This changes also bumps the version of certbot required by certbot-nginx
and certbot-apache to take use of the new display_util function.
* fix certbot_compatibility_test
since the http plugins now require IDisplay, we need to inject it
* fix dependency version on certbot
* use better asserts
* try fix oldest deps
because certbot 1.10.0 depends on acme>=1.8.0, we need to use
acme==1.8.0 in the -oldest tests
* cli: redesign output of new certificate reporting
Changes the output of run, certonly and certonly --csr. No longer uses
IReporter.
* cli: redesign output of failed authz reporting
* fix problem sorting to be stable between py2 & 3
* add some catch-all error text
* cli: dont use IReporter for EFF donation prompt
* add per-authenticator hints
* pass achalls to auth_hint, write some tests
* exclude static auth hints from coverage
* dont call auth_hint unless derived from .Plugin
* dns fallback hint: dont assume --dns-blah works
--dns-blah won't work for third-party plugins, they need to be specified
using --authenticator dns-blah.
* add code comments about the auth_hint interface
* renew: don't restart the installer for dry-runs
Prevents Certbot from superfluously invoking the installer restart
during dry-run renewals. (This does not affect authenticator restarts).
Additionally removes some CLI output that was reporting the fullchain
path of the renewed certificate.
* update CHANGELOG.md
* cli: redesign output when cert installation failed
- Display a message when certificate installation begins.
- Don't use IReporter, just log errors immediately if restart/rollback
fails.
- Prompt the user with a command to retry the installation process once
they have fixed any underlying problems.
* vary by preconfigured_renewal
and move expiry date to be above the renewal advice
* update code comment
Co-authored-by: ohemorange <ebportnoy@gmail.com>
* update code comment
Co-authored-by: ohemorange <ebportnoy@gmail.com>
* fix lint
* derve cert name from cert_path, if possible
* fix type annotation
* text change in nginx hint
Co-authored-by: ohemorange <ebportnoy@gmail.com>
* print message when restarting server after renewal
* log: print "advice" when exiting with an error
When running in non-quiet mode.
* try fix -oldest lock_test.py
* fix docstring
* s/Restarting/Reloading/ when notifying the user
* fix test name
Co-authored-by: ohemorange <ebportnoy@gmail.com>
* type annotations
* s/using the {} plugin/installer: {}/
* copy: avoid "plugin" where possible
* link to user guide#automated-renewals
when not running with --preconfigured-renewal
* cli: reduce default logging verbosity
* fix lock_test: -vv is needed to see logger.debug
* Change comment in log.py to match the change to default verbosity
* Audit and adjust logging levels in apache module
* Audit and adjust logging levels in nginx module
* Audit, adjust logging levels, and improve logging calls in certbot module
* Fix tests to mock correct methods and classes
* typo in non-preconfigured-renewal message
Co-authored-by: ohemorange <ebportnoy@gmail.com>
* fix test
* revert acme version bump
* catch up to python3 changes
* Revert "revert acme version bump"
This reverts commit fa83d6a51cf8d0e7e17da53c6b751ad12945d0cf.
* Change ocsp check error to warning since it's non-fatal
* Update storage_test in parallel with last change
* get rid of leading newline on "Deploying [...]"
* shrink renewal and installation success messages
* print logfile rather than logdir in exit handler
* Decrease logging level to info for idempotent operation where enhancement is already set
* Display cert not yet due for renewal message when renewing and no other action will be taken, and change cert to certificate
* also write to logger so it goes in the log file
* Don't double write to log file; fix main test
* cli: remove trailing newline on new cert reporting
* ignore type error
* revert accidental changes to dependencies
* Pass tests in any timezone by using utcfromtimestamp
* Add changelog entry
* fix nits
* Improve wording of try again message
* minor wording change to changelog
* hooks: send hook stdout to CLI stdout
includes both --manual and --{pre,post,renew} hooks
* update docstrings and remove TODO
* add a pending deprecation on execute_command
* add test coverage for both
* update deprecation text
Co-authored-by: ohemorange <ebportnoy@gmail.com>
Co-authored-by: Alex Zorin <alex@zorin.id.au>
Co-authored-by: alexzorin <alex@zor.io>
2021-05-24 20:47:39 -04:00
|
|
|
with mock.patch("certbot_apache._internal.configurator.logger.error") as mock_log:
|
2023-02-16 00:02:02 -05:00
|
|
|
with pytest.raises(errors.PluginError):
|
|
|
|
|
self.config.enhance("certbot.demo", "redirect")
|
2018-04-18 14:08:30 -04:00
|
|
|
# Check that correct logger.warning was printed
|
2023-02-16 00:02:02 -05:00
|
|
|
assert "not able to find" in mock_log.call_args[0][0]
|
|
|
|
|
assert "\"redirect\"" in mock_log.call_args[0][0]
|
2018-04-18 14:08:30 -04:00
|
|
|
|
|
|
|
|
mock_log.reset_mock()
|
|
|
|
|
|
2023-02-16 00:02:02 -05:00
|
|
|
with pytest.raises(errors.PluginError):
|
|
|
|
|
self.config.enhance("certbot.demo", "ensure-http-header", "Test")
|
2018-04-18 14:08:30 -04:00
|
|
|
# Check that correct logger.warning was printed
|
2023-02-16 00:02:02 -05:00
|
|
|
assert "not able to find" in mock_log.call_args[0][0]
|
|
|
|
|
assert "Test" in mock_log.call_args[0][0]
|
2018-04-18 14:08:30 -04:00
|
|
|
|
2016-05-26 14:43:00 -04:00
|
|
|
@mock.patch("certbot.util.exe_exists")
|
Distribution specific override functionality based on class inheritance (#5202)
Class inheritance based approach to distro specific overrides.
How it works:
The certbot-apache plugin entrypoint has been changed to entrypoint.ENTRYPOINT which is a variable containing appropriate override class for system, if available.
Override classes register themselves using decorator override.register() which takes a list of distribution fingerprints (ID & LIKE variables in /etc/os-release, or platform.linux_distribution() as a fallback). These end up as keys in dict override.OVERRIDE_CLASSES and values for the keys are references to the class that called the decorator, hence allowing self-registration of override classes when they are imported. The only file importing these override classes is entrypoint.py, so adding new override classes would need only one import in addition to the actual override class file.
Generic changes:
Parser initialization has been moved to separate class method, allowing easy override where needed.
Cleaned up configurator.py a bit, and moved some helper functions to newly created apache_util.py
Split Debian specific code from configurator.py to debian_override.py
Changed define_cmd to apache_cmd because the parameters are for every distribution supporting this behavior, and we're able to use the value to build the additional configuration dump commands.
Moved add_parser_mod() from configurator to parser add_mod()
Added two new configuration dump parsing methods to update_runtime_variables() in parser: update_includes() and update_modules().
Changed init_modules() in parser to accommodate the changes above. (ie. don't throw existing self.modules out).
Moved OS based constants to their respective override classes.
Refactored configurator class discovery in tests to help easier test case creation using distribution based override configurator class.
tests.util.get_apache_configurator() now takes keyword argument os_info which is string of the desired mock OS fingerprint response that's used for picking the right override class.
This PR includes two major generic additions that should vastly improve our parsing accuracy and quality:
Includes are parsed from config dump from httpd binary. This is mandatory for some distributions (Like OpenSUSE) to get visibility over the whole configuration tree because of Include statements passed on in command line, and not via root httpd.conf file.
Modules are parsed from config dump from httpd binary. This lets us jump into correct IfModule directives if for some reason we have missed the module availability (because of one being included on command line or such).
Distribution specific changes
Because of the generic changes, there are two distributions (or distribution families) that do not provide such functionality, so it had to be overridden in their respective override files. These distributions are:
CentOS, because it deliberately limits httpd binary stdout using SELinux as a feature. We are doing opportunistic config dumps here however, in case SELinux enforcing is off.
Gentoo, because it does not provide a way to invoke httpd with command line parsed from its specific configuration file. Gentoo relies heavily on Define statements that are passed over from APACHE2_OPTS variable /etc/conf.d/apache2 file and most of the configuration in root Apache configuration are dependent on these values.
Debian
Moved the Debian specific parts from configurator.py to Debian specific override.
CentOS
Parsing of /etc/sysconfig/httpd file for additional Define statements. This could hold other parameters too, but parsing everything off it would require a full Apache lexer. For CLI parameters, I think Defines are the most common ones. This is done in addition of opportunistic parsing of httpd binary config dump.
Added CentOS default Apache configuration tree for realistic test cases.
Gentoo
Parsing Defines from /etc/conf.d/apache2 variable APACHE2_OPTS, which holds additional Define statements to enable certain functionalities, enabling parts of the configuration in the Apache2 DOM. This is done instead of trying to parse httpd binary configuration dumps.
Added default Apache configuration from Gentoo to testdata, including /etc/conf.d/apache2 file for realistic test cases.
* Distribution specific override functionality based on class inheritance
* Need to patch get_systemd_os_like to as travis has proper os-release
* Added pydoc
* Move parser initialization to a method and fix Python 3 __new__ errors
* Parser changes to parse HTTPD config
* Try to get modules and includes from httpd process for better visibility over the configuration
* Had to disable duplicate-code because of test setup (PyCQA/pylint/issues/214)
* CentOS tests and linter fixes
* Gentoo override, tests and linter fixes
* Mock the process call in all the tests that require it
* Fix CentOS test mock
* Restore reseting modules list functionality for cleanup
* Move OS fingerprinting and constant mocks to parent class
* Fixes requested in review
* New entrypoint structure and started moving OS constants to override classes
* OS constants move continued, test and linter fixes
* Removed dead code
* Apache compatibility test changest to reflect OS constant restructure
* Test fix
* Requested changes
* Moved Debian specific tests to own test file
* Removed decorator based override class registration in favor of entrypoint dict
* Fix for update_includes for some versions of Augeas
* Take fedora fix into account in tests
* Review fixes
2017-12-04 14:49:18 -05:00
|
|
|
def test_ocsp_stapling(self, mock_exe):
|
2016-05-19 19:04:18 -04:00
|
|
|
self.config.parser.update_runtime_variables = mock.Mock()
|
2020-03-23 19:49:52 -04:00
|
|
|
self.config.parser.modules["mod_ssl.c"] = None
|
|
|
|
|
self.config.parser.modules["socache_shmcb_module"] = None
|
2016-05-19 19:04:18 -04:00
|
|
|
self.config.get_version = mock.Mock(return_value=(2, 4, 7))
|
|
|
|
|
mock_exe.return_value = True
|
|
|
|
|
|
|
|
|
|
# This will create an ssl vhost for certbot.demo
|
2018-04-18 14:08:30 -04:00
|
|
|
self.config.choose_vhost("certbot.demo")
|
2016-05-19 19:04:18 -04:00
|
|
|
self.config.enhance("certbot.demo", "staple-ocsp")
|
|
|
|
|
|
|
|
|
|
# Get the ssl vhost for certbot.demo
|
|
|
|
|
ssl_vhost = self.config.assoc["certbot.demo"]
|
|
|
|
|
|
|
|
|
|
ssl_use_stapling_aug_path = self.config.parser.find_dir(
|
|
|
|
|
"SSLUseStapling", "on", ssl_vhost.path)
|
|
|
|
|
|
2023-02-16 00:02:02 -05:00
|
|
|
assert len(ssl_use_stapling_aug_path) == 1
|
2016-05-19 19:04:18 -04:00
|
|
|
|
|
|
|
|
ssl_vhost_aug_path = parser.get_aug_path(ssl_vhost.filep)
|
|
|
|
|
stapling_cache_aug_path = self.config.parser.find_dir('SSLStaplingCache',
|
|
|
|
|
"shmcb:/var/run/apache2/stapling_cache(128000)",
|
|
|
|
|
ssl_vhost_aug_path)
|
|
|
|
|
|
2023-02-16 00:02:02 -05:00
|
|
|
assert len(stapling_cache_aug_path) == 1
|
2016-05-19 19:04:18 -04:00
|
|
|
|
2016-05-26 14:43:00 -04:00
|
|
|
@mock.patch("certbot.util.exe_exists")
|
2016-05-19 19:04:18 -04:00
|
|
|
def test_ocsp_stapling_twice(self, mock_exe):
|
|
|
|
|
self.config.parser.update_runtime_variables = mock.Mock()
|
2020-03-23 19:49:52 -04:00
|
|
|
self.config.parser.modules["mod_ssl.c"] = None
|
|
|
|
|
self.config.parser.modules["socache_shmcb_module"] = None
|
2016-05-19 19:04:18 -04:00
|
|
|
self.config.get_version = mock.Mock(return_value=(2, 4, 7))
|
|
|
|
|
mock_exe.return_value = True
|
|
|
|
|
|
|
|
|
|
# Checking the case with already enabled ocsp stapling configuration
|
2018-04-18 14:08:30 -04:00
|
|
|
self.config.choose_vhost("ocspvhost.com")
|
2016-05-19 19:04:18 -04:00
|
|
|
self.config.enhance("ocspvhost.com", "staple-ocsp")
|
|
|
|
|
|
|
|
|
|
# Get the ssl vhost for letsencrypt.demo
|
|
|
|
|
ssl_vhost = self.config.assoc["ocspvhost.com"]
|
|
|
|
|
|
|
|
|
|
ssl_use_stapling_aug_path = self.config.parser.find_dir(
|
|
|
|
|
"SSLUseStapling", "on", ssl_vhost.path)
|
|
|
|
|
|
2023-02-16 00:02:02 -05:00
|
|
|
assert len(ssl_use_stapling_aug_path) == 1
|
2016-05-19 19:04:18 -04:00
|
|
|
ssl_vhost_aug_path = parser.get_aug_path(ssl_vhost.filep)
|
|
|
|
|
stapling_cache_aug_path = self.config.parser.find_dir('SSLStaplingCache',
|
|
|
|
|
"shmcb:/var/run/apache2/stapling_cache(128000)",
|
|
|
|
|
ssl_vhost_aug_path)
|
|
|
|
|
|
2023-02-16 00:02:02 -05:00
|
|
|
assert len(stapling_cache_aug_path) == 1
|
2016-05-19 19:04:18 -04:00
|
|
|
|
|
|
|
|
def test_get_http_vhost_third_filter(self):
|
|
|
|
|
ssl_vh = obj.VirtualHost(
|
2020-04-13 13:41:39 -04:00
|
|
|
"fp", "ap", {obj.Addr(("*", "443"))},
|
2016-05-19 19:04:18 -04:00
|
|
|
True, False)
|
|
|
|
|
ssl_vh.name = "satoshi.com"
|
|
|
|
|
self.config.vhosts.append(ssl_vh)
|
|
|
|
|
|
|
|
|
|
# pylint: disable=protected-access
|
|
|
|
|
http_vh = self.config._get_http_vhost(ssl_vh)
|
2023-02-16 00:02:02 -05:00
|
|
|
assert http_vh.ssl is False
|
2016-05-19 19:04:18 -04:00
|
|
|
|
2016-05-26 14:43:00 -04:00
|
|
|
@mock.patch("certbot.util.run_script")
|
|
|
|
|
@mock.patch("certbot.util.exe_exists")
|
2015-11-07 23:37:57 -05:00
|
|
|
def test_http_header_hsts(self, mock_exe, _):
|
2015-11-06 17:32:02 -05:00
|
|
|
self.config.parser.update_runtime_variables = mock.Mock()
|
2020-03-23 19:49:52 -04:00
|
|
|
self.config.parser.modules["mod_ssl.c"] = None
|
|
|
|
|
self.config.parser.modules["headers_module"] = None
|
2015-11-06 17:32:02 -05:00
|
|
|
mock_exe.return_value = True
|
|
|
|
|
|
2016-04-13 19:30:57 -04:00
|
|
|
# This will create an ssl vhost for certbot.demo
|
2018-04-18 14:08:30 -04:00
|
|
|
self.config.choose_vhost("certbot.demo")
|
2016-04-13 19:30:57 -04:00
|
|
|
self.config.enhance("certbot.demo", "ensure-http-header",
|
2016-01-14 06:25:15 -05:00
|
|
|
"Strict-Transport-Security")
|
2015-11-06 17:32:02 -05:00
|
|
|
|
2016-04-13 19:30:57 -04:00
|
|
|
# Get the ssl vhost for certbot.demo
|
|
|
|
|
ssl_vhost = self.config.assoc["certbot.demo"]
|
2015-11-06 17:32:02 -05:00
|
|
|
|
|
|
|
|
# These are not immediately available in find_dir even with save() and
|
|
|
|
|
# load(). They must be found in sites-available
|
|
|
|
|
hsts_header = self.config.parser.find_dir(
|
2016-01-14 06:25:15 -05:00
|
|
|
"Header", None, ssl_vhost.path)
|
2015-11-07 23:37:57 -05:00
|
|
|
|
|
|
|
|
# four args to HSTS header
|
2023-02-16 00:02:02 -05:00
|
|
|
assert len(hsts_header) == 4
|
2015-11-07 23:37:57 -05:00
|
|
|
|
2015-11-08 10:21:36 -05:00
|
|
|
def test_http_header_hsts_twice(self):
|
2020-03-23 19:49:52 -04:00
|
|
|
self.config.parser.modules["mod_ssl.c"] = None
|
2015-11-08 10:21:36 -05:00
|
|
|
# skip the enable mod
|
2020-03-23 19:49:52 -04:00
|
|
|
self.config.parser.modules["headers_module"] = None
|
2015-11-07 23:37:57 -05:00
|
|
|
|
2018-04-18 14:08:30 -04:00
|
|
|
# This will create an ssl vhost for encryption-example.demo
|
|
|
|
|
self.config.choose_vhost("encryption-example.demo")
|
2015-11-24 18:33:21 -05:00
|
|
|
self.config.enhance("encryption-example.demo", "ensure-http-header",
|
2016-01-14 06:25:15 -05:00
|
|
|
"Strict-Transport-Security")
|
2015-11-07 23:37:57 -05:00
|
|
|
|
2023-02-16 00:02:02 -05:00
|
|
|
with pytest.raises(errors.PluginEnhancementAlreadyPresent):
|
|
|
|
|
self.config.enhance("encryption-example.demo",
|
2016-01-14 06:25:15 -05:00
|
|
|
"ensure-http-header", "Strict-Transport-Security")
|
2015-11-06 17:32:02 -05:00
|
|
|
|
2016-05-26 14:43:00 -04:00
|
|
|
@mock.patch("certbot.util.run_script")
|
|
|
|
|
@mock.patch("certbot.util.exe_exists")
|
2015-11-09 17:36:00 -05:00
|
|
|
def test_http_header_uir(self, mock_exe, _):
|
|
|
|
|
self.config.parser.update_runtime_variables = mock.Mock()
|
2020-03-23 19:49:52 -04:00
|
|
|
self.config.parser.modules["mod_ssl.c"] = None
|
|
|
|
|
self.config.parser.modules["headers_module"] = None
|
Distribution specific override functionality based on class inheritance (#5202)
Class inheritance based approach to distro specific overrides.
How it works:
The certbot-apache plugin entrypoint has been changed to entrypoint.ENTRYPOINT which is a variable containing appropriate override class for system, if available.
Override classes register themselves using decorator override.register() which takes a list of distribution fingerprints (ID & LIKE variables in /etc/os-release, or platform.linux_distribution() as a fallback). These end up as keys in dict override.OVERRIDE_CLASSES and values for the keys are references to the class that called the decorator, hence allowing self-registration of override classes when they are imported. The only file importing these override classes is entrypoint.py, so adding new override classes would need only one import in addition to the actual override class file.
Generic changes:
Parser initialization has been moved to separate class method, allowing easy override where needed.
Cleaned up configurator.py a bit, and moved some helper functions to newly created apache_util.py
Split Debian specific code from configurator.py to debian_override.py
Changed define_cmd to apache_cmd because the parameters are for every distribution supporting this behavior, and we're able to use the value to build the additional configuration dump commands.
Moved add_parser_mod() from configurator to parser add_mod()
Added two new configuration dump parsing methods to update_runtime_variables() in parser: update_includes() and update_modules().
Changed init_modules() in parser to accommodate the changes above. (ie. don't throw existing self.modules out).
Moved OS based constants to their respective override classes.
Refactored configurator class discovery in tests to help easier test case creation using distribution based override configurator class.
tests.util.get_apache_configurator() now takes keyword argument os_info which is string of the desired mock OS fingerprint response that's used for picking the right override class.
This PR includes two major generic additions that should vastly improve our parsing accuracy and quality:
Includes are parsed from config dump from httpd binary. This is mandatory for some distributions (Like OpenSUSE) to get visibility over the whole configuration tree because of Include statements passed on in command line, and not via root httpd.conf file.
Modules are parsed from config dump from httpd binary. This lets us jump into correct IfModule directives if for some reason we have missed the module availability (because of one being included on command line or such).
Distribution specific changes
Because of the generic changes, there are two distributions (or distribution families) that do not provide such functionality, so it had to be overridden in their respective override files. These distributions are:
CentOS, because it deliberately limits httpd binary stdout using SELinux as a feature. We are doing opportunistic config dumps here however, in case SELinux enforcing is off.
Gentoo, because it does not provide a way to invoke httpd with command line parsed from its specific configuration file. Gentoo relies heavily on Define statements that are passed over from APACHE2_OPTS variable /etc/conf.d/apache2 file and most of the configuration in root Apache configuration are dependent on these values.
Debian
Moved the Debian specific parts from configurator.py to Debian specific override.
CentOS
Parsing of /etc/sysconfig/httpd file for additional Define statements. This could hold other parameters too, but parsing everything off it would require a full Apache lexer. For CLI parameters, I think Defines are the most common ones. This is done in addition of opportunistic parsing of httpd binary config dump.
Added CentOS default Apache configuration tree for realistic test cases.
Gentoo
Parsing Defines from /etc/conf.d/apache2 variable APACHE2_OPTS, which holds additional Define statements to enable certain functionalities, enabling parts of the configuration in the Apache2 DOM. This is done instead of trying to parse httpd binary configuration dumps.
Added default Apache configuration from Gentoo to testdata, including /etc/conf.d/apache2 file for realistic test cases.
* Distribution specific override functionality based on class inheritance
* Need to patch get_systemd_os_like to as travis has proper os-release
* Added pydoc
* Move parser initialization to a method and fix Python 3 __new__ errors
* Parser changes to parse HTTPD config
* Try to get modules and includes from httpd process for better visibility over the configuration
* Had to disable duplicate-code because of test setup (PyCQA/pylint/issues/214)
* CentOS tests and linter fixes
* Gentoo override, tests and linter fixes
* Mock the process call in all the tests that require it
* Fix CentOS test mock
* Restore reseting modules list functionality for cleanup
* Move OS fingerprinting and constant mocks to parent class
* Fixes requested in review
* New entrypoint structure and started moving OS constants to override classes
* OS constants move continued, test and linter fixes
* Removed dead code
* Apache compatibility test changest to reflect OS constant restructure
* Test fix
* Requested changes
* Moved Debian specific tests to own test file
* Removed decorator based override class registration in favor of entrypoint dict
* Fix for update_includes for some versions of Augeas
* Take fedora fix into account in tests
* Review fixes
2017-12-04 14:49:18 -05:00
|
|
|
|
2015-11-09 17:36:00 -05:00
|
|
|
mock_exe.return_value = True
|
|
|
|
|
|
2016-04-13 19:30:57 -04:00
|
|
|
# This will create an ssl vhost for certbot.demo
|
2018-04-18 14:08:30 -04:00
|
|
|
self.config.choose_vhost("certbot.demo")
|
2016-04-13 19:30:57 -04:00
|
|
|
self.config.enhance("certbot.demo", "ensure-http-header",
|
2016-01-14 06:25:15 -05:00
|
|
|
"Upgrade-Insecure-Requests")
|
2015-11-09 17:36:00 -05:00
|
|
|
|
2023-02-16 00:02:02 -05:00
|
|
|
assert "headers_module" in self.config.parser.modules
|
2015-11-09 17:36:00 -05:00
|
|
|
|
2016-04-13 19:30:57 -04:00
|
|
|
# Get the ssl vhost for certbot.demo
|
|
|
|
|
ssl_vhost = self.config.assoc["certbot.demo"]
|
2015-11-09 17:36:00 -05:00
|
|
|
|
|
|
|
|
# These are not immediately available in find_dir even with save() and
|
|
|
|
|
# load(). They must be found in sites-available
|
|
|
|
|
uir_header = self.config.parser.find_dir(
|
2016-01-14 06:25:15 -05:00
|
|
|
"Header", None, ssl_vhost.path)
|
2015-11-09 17:36:00 -05:00
|
|
|
|
|
|
|
|
# four args to HSTS header
|
2023-02-16 00:02:02 -05:00
|
|
|
assert len(uir_header) == 4
|
2015-11-09 17:36:00 -05:00
|
|
|
|
|
|
|
|
def test_http_header_uir_twice(self):
|
2020-03-23 19:49:52 -04:00
|
|
|
self.config.parser.modules["mod_ssl.c"] = None
|
2015-11-09 17:36:00 -05:00
|
|
|
# skip the enable mod
|
2020-03-23 19:49:52 -04:00
|
|
|
self.config.parser.modules["headers_module"] = None
|
2015-11-09 17:36:00 -05:00
|
|
|
|
2018-04-18 14:08:30 -04:00
|
|
|
# This will create an ssl vhost for encryption-example.demo
|
|
|
|
|
self.config.choose_vhost("encryption-example.demo")
|
2015-11-24 18:33:21 -05:00
|
|
|
self.config.enhance("encryption-example.demo", "ensure-http-header",
|
2016-01-14 06:25:15 -05:00
|
|
|
"Upgrade-Insecure-Requests")
|
2015-11-09 17:36:00 -05:00
|
|
|
|
2023-02-16 00:02:02 -05:00
|
|
|
with pytest.raises(errors.PluginEnhancementAlreadyPresent):
|
|
|
|
|
self.config.enhance("encryption-example.demo",
|
2016-01-14 06:25:15 -05:00
|
|
|
"ensure-http-header", "Upgrade-Insecure-Requests")
|
2015-11-06 17:32:02 -05:00
|
|
|
|
2016-05-26 14:43:00 -04:00
|
|
|
@mock.patch("certbot.util.run_script")
|
|
|
|
|
@mock.patch("certbot.util.exe_exists")
|
2015-07-30 02:40:07 -04:00
|
|
|
def test_redirect_well_formed_http(self, mock_exe, _):
|
2020-03-23 19:49:52 -04:00
|
|
|
self.config.parser.modules["rewrite_module"] = None
|
2015-07-30 02:40:07 -04:00
|
|
|
self.config.parser.update_runtime_variables = mock.Mock()
|
|
|
|
|
mock_exe.return_value = True
|
2015-12-02 20:40:12 -05:00
|
|
|
self.config.get_version = mock.Mock(return_value=(2, 2))
|
|
|
|
|
|
2016-04-13 19:30:57 -04:00
|
|
|
# This will create an ssl vhost for certbot.demo
|
2018-04-18 14:08:30 -04:00
|
|
|
self.config.choose_vhost("certbot.demo")
|
2016-04-13 19:30:57 -04:00
|
|
|
self.config.enhance("certbot.demo", "redirect")
|
2015-07-22 05:05:01 -04:00
|
|
|
|
|
|
|
|
# These are not immediately available in find_dir even with save() and
|
|
|
|
|
# load(). They must be found in sites-available
|
|
|
|
|
rw_engine = self.config.parser.find_dir(
|
|
|
|
|
"RewriteEngine", "on", self.vh_truth[3].path)
|
|
|
|
|
rw_rule = self.config.parser.find_dir(
|
|
|
|
|
"RewriteRule", None, self.vh_truth[3].path)
|
|
|
|
|
|
2023-02-16 00:02:02 -05:00
|
|
|
assert len(rw_engine) == 1
|
2015-07-22 05:05:01 -04:00
|
|
|
# three args to rw_rule
|
2023-02-16 00:02:02 -05:00
|
|
|
assert len(rw_rule) == 3
|
2015-07-22 05:05:01 -04:00
|
|
|
|
2016-09-28 14:34:27 -04:00
|
|
|
# [:-3] to remove the vhost index number
|
2023-02-16 00:02:02 -05:00
|
|
|
assert rw_engine[0].startswith(self.vh_truth[3].path[:-3]) is True
|
|
|
|
|
assert rw_rule[0].startswith(self.vh_truth[3].path[:-3]) is True
|
2015-07-22 05:05:01 -04:00
|
|
|
|
2015-12-03 21:00:24 -05:00
|
|
|
def test_rewrite_rule_exists(self):
|
2015-12-02 20:40:12 -05:00
|
|
|
# Skip the enable mod
|
2020-03-23 19:49:52 -04:00
|
|
|
self.config.parser.modules["rewrite_module"] = None
|
2015-12-02 20:40:12 -05:00
|
|
|
self.config.get_version = mock.Mock(return_value=(2, 3, 9))
|
|
|
|
|
self.config.parser.add_dir(
|
|
|
|
|
self.vh_truth[3].path, "RewriteRule", ["Unknown"])
|
2016-01-14 06:25:15 -05:00
|
|
|
# pylint: disable=protected-access
|
2023-02-16 00:02:02 -05:00
|
|
|
assert self.config._is_rewrite_exists(self.vh_truth[3]) is True
|
2015-12-03 21:00:24 -05:00
|
|
|
|
|
|
|
|
def test_rewrite_engine_exists(self):
|
|
|
|
|
# Skip the enable mod
|
2020-03-23 19:49:52 -04:00
|
|
|
self.config.parser.modules["rewrite_module"] = None
|
2015-12-03 21:00:24 -05:00
|
|
|
self.config.get_version = mock.Mock(return_value=(2, 3, 9))
|
|
|
|
|
self.config.parser.add_dir(
|
|
|
|
|
self.vh_truth[3].path, "RewriteEngine", "on")
|
2016-01-14 06:25:15 -05:00
|
|
|
# pylint: disable=protected-access
|
2023-02-16 00:02:02 -05:00
|
|
|
assert self.config._is_rewrite_engine_on(self.vh_truth[3])
|
2015-12-02 20:40:12 -05:00
|
|
|
|
2016-05-26 14:43:00 -04:00
|
|
|
@mock.patch("certbot.util.run_script")
|
|
|
|
|
@mock.patch("certbot.util.exe_exists")
|
2015-12-02 20:40:12 -05:00
|
|
|
def test_redirect_with_existing_rewrite(self, mock_exe, _):
|
2020-03-23 19:49:52 -04:00
|
|
|
self.config.parser.modules["rewrite_module"] = None
|
2015-12-02 20:40:12 -05:00
|
|
|
self.config.parser.update_runtime_variables = mock.Mock()
|
|
|
|
|
mock_exe.return_value = True
|
2016-05-19 19:04:18 -04:00
|
|
|
self.config.get_version = mock.Mock(return_value=(2, 2, 0))
|
2015-12-02 20:40:12 -05:00
|
|
|
|
|
|
|
|
# Create a preexisting rewrite rule
|
|
|
|
|
self.config.parser.add_dir(
|
2016-01-11 14:12:30 -05:00
|
|
|
self.vh_truth[3].path, "RewriteRule", ["UnknownPattern",
|
2016-01-14 06:25:15 -05:00
|
|
|
"UnknownTarget"])
|
2015-12-02 20:40:12 -05:00
|
|
|
self.config.save()
|
|
|
|
|
|
2016-04-13 19:30:57 -04:00
|
|
|
# This will create an ssl vhost for certbot.demo
|
2018-04-18 14:08:30 -04:00
|
|
|
self.config.choose_vhost("certbot.demo")
|
2016-04-13 19:30:57 -04:00
|
|
|
self.config.enhance("certbot.demo", "redirect")
|
2015-12-02 20:40:12 -05:00
|
|
|
|
|
|
|
|
# These are not immediately available in find_dir even with save() and
|
|
|
|
|
# load(). They must be found in sites-available
|
|
|
|
|
rw_engine = self.config.parser.find_dir(
|
|
|
|
|
"RewriteEngine", "on", self.vh_truth[3].path)
|
|
|
|
|
rw_rule = self.config.parser.find_dir(
|
|
|
|
|
"RewriteRule", None, self.vh_truth[3].path)
|
|
|
|
|
|
2023-02-16 00:02:02 -05:00
|
|
|
assert len(rw_engine) == 1
|
2015-12-02 20:40:12 -05:00
|
|
|
# three args to rw_rule + 1 arg for the pre existing rewrite
|
2023-02-16 00:02:02 -05:00
|
|
|
assert len(rw_rule) == 5
|
2016-09-28 14:34:27 -04:00
|
|
|
# [:-3] to remove the vhost index number
|
2023-02-16 00:02:02 -05:00
|
|
|
assert rw_engine[0].startswith(self.vh_truth[3].path[:-3]) is True
|
|
|
|
|
assert rw_rule[0].startswith(self.vh_truth[3].path[:-3]) is True
|
2015-12-02 20:40:12 -05:00
|
|
|
|
2023-02-16 00:02:02 -05:00
|
|
|
assert "rewrite_module" in self.config.parser.modules
|
2015-12-02 20:40:12 -05:00
|
|
|
|
2017-03-02 19:49:34 -05:00
|
|
|
@mock.patch("certbot.util.run_script")
|
|
|
|
|
@mock.patch("certbot.util.exe_exists")
|
|
|
|
|
def test_redirect_with_old_https_redirection(self, mock_exe, _):
|
2020-03-23 19:49:52 -04:00
|
|
|
self.config.parser.modules["rewrite_module"] = None
|
2017-03-02 19:49:34 -05:00
|
|
|
self.config.parser.update_runtime_variables = mock.Mock()
|
|
|
|
|
mock_exe.return_value = True
|
2022-08-29 13:05:48 -04:00
|
|
|
self.config.get_version = mock.Mock(return_value=(2, 4, 0))
|
2017-03-02 19:49:34 -05:00
|
|
|
|
|
|
|
|
ssl_vhost = self.config.choose_vhost("certbot.demo")
|
|
|
|
|
|
|
|
|
|
# pylint: disable=protected-access
|
|
|
|
|
http_vhost = self.config._get_http_vhost(ssl_vhost)
|
|
|
|
|
|
|
|
|
|
# Create an old (previously suppoorted) https redirectoin rewrite rule
|
|
|
|
|
self.config.parser.add_dir(
|
|
|
|
|
http_vhost.path, "RewriteRule",
|
|
|
|
|
["^",
|
|
|
|
|
"https://%{SERVER_NAME}%{REQUEST_URI}",
|
|
|
|
|
"[L,QSA,R=permanent]"])
|
|
|
|
|
|
|
|
|
|
self.config.save()
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
self.config.enhance("certbot.demo", "redirect")
|
|
|
|
|
except errors.PluginEnhancementAlreadyPresent:
|
|
|
|
|
args_paths = self.config.parser.find_dir(
|
|
|
|
|
"RewriteRule", None, http_vhost.path, False)
|
2019-06-28 11:39:13 -04:00
|
|
|
arg_vals = [self.config.parser.aug.get(x) for x in args_paths]
|
2023-02-16 00:02:02 -05:00
|
|
|
assert arg_vals == constants.REWRITE_HTTPS_ARGS
|
2017-03-02 19:49:34 -05:00
|
|
|
|
|
|
|
|
|
2015-07-24 06:22:35 -04:00
|
|
|
def test_redirect_with_conflict(self):
|
2020-03-23 19:49:52 -04:00
|
|
|
self.config.parser.modules["rewrite_module"] = None
|
2015-07-24 06:22:35 -04:00
|
|
|
ssl_vh = obj.VirtualHost(
|
2020-04-13 13:41:39 -04:00
|
|
|
"fp", "ap", {obj.Addr(("*", "443")),
|
|
|
|
|
obj.Addr(("zombo.com",))},
|
2015-07-24 06:22:35 -04:00
|
|
|
True, False)
|
|
|
|
|
# No names ^ this guy should conflict.
|
|
|
|
|
|
|
|
|
|
# pylint: disable=protected-access
|
2023-02-16 00:02:02 -05:00
|
|
|
with pytest.raises(errors.PluginError):
|
|
|
|
|
self.config._enable_redirect(ssl_vh, "")
|
2015-07-24 06:22:35 -04:00
|
|
|
|
2016-05-19 12:40:17 -04:00
|
|
|
def test_redirect_two_domains_one_vhost(self):
|
2015-07-22 05:05:01 -04:00
|
|
|
# Skip the enable mod
|
2020-03-23 19:49:52 -04:00
|
|
|
self.config.parser.modules["rewrite_module"] = None
|
2015-12-02 17:00:07 -05:00
|
|
|
self.config.get_version = mock.Mock(return_value=(2, 3, 9))
|
|
|
|
|
|
2018-04-18 14:08:30 -04:00
|
|
|
# Creates ssl vhost for the domain
|
|
|
|
|
self.config.choose_vhost("red.blue.purple.com")
|
|
|
|
|
|
2016-05-19 12:40:17 -04:00
|
|
|
self.config.enhance("red.blue.purple.com", "redirect")
|
2019-11-25 12:44:40 -05:00
|
|
|
verify_no_redirect = ("certbot_apache._internal.configurator."
|
2016-05-19 12:40:17 -04:00
|
|
|
"ApacheConfigurator._verify_no_certbot_redirect")
|
|
|
|
|
with mock.patch(verify_no_redirect) as mock_verify:
|
|
|
|
|
self.config.enhance("green.blue.purple.com", "redirect")
|
2023-02-16 00:02:02 -05:00
|
|
|
assert mock_verify.called is False
|
2016-05-19 12:40:17 -04:00
|
|
|
|
|
|
|
|
def test_redirect_from_previous_run(self):
|
|
|
|
|
# Skip the enable mod
|
2020-03-23 19:49:52 -04:00
|
|
|
self.config.parser.modules["rewrite_module"] = None
|
2016-05-19 12:40:17 -04:00
|
|
|
self.config.get_version = mock.Mock(return_value=(2, 3, 9))
|
2018-04-18 14:08:30 -04:00
|
|
|
self.config.choose_vhost("red.blue.purple.com")
|
2016-05-19 12:40:17 -04:00
|
|
|
self.config.enhance("red.blue.purple.com", "redirect")
|
|
|
|
|
# Clear state about enabling redirect on this run
|
|
|
|
|
# pylint: disable=protected-access
|
|
|
|
|
self.config._enhanced_vhosts["redirect"].clear()
|
|
|
|
|
|
2023-02-16 00:02:02 -05:00
|
|
|
with pytest.raises(errors.PluginEnhancementAlreadyPresent):
|
|
|
|
|
self.config.enhance("green.blue.purple.com", "redirect")
|
2015-07-22 05:05:01 -04:00
|
|
|
|
2015-07-24 06:22:35 -04:00
|
|
|
def test_create_own_redirect(self):
|
2020-03-23 19:49:52 -04:00
|
|
|
self.config.parser.modules["rewrite_module"] = None
|
2015-12-02 18:05:49 -05:00
|
|
|
self.config.get_version = mock.Mock(return_value=(2, 3, 9))
|
2015-07-24 06:22:35 -04:00
|
|
|
# For full testing... give names...
|
|
|
|
|
self.vh_truth[1].name = "default.com"
|
2020-04-13 13:41:39 -04:00
|
|
|
self.vh_truth[1].aliases = {"yes.default.com"}
|
2015-07-22 05:05:01 -04:00
|
|
|
|
2016-01-14 06:25:15 -05:00
|
|
|
# pylint: disable=protected-access
|
|
|
|
|
self.config._enable_redirect(self.vh_truth[1], "")
|
2023-02-16 00:02:02 -05:00
|
|
|
assert len(self.config.vhosts) == 13
|
2015-07-22 05:05:01 -04:00
|
|
|
|
2015-12-02 20:40:12 -05:00
|
|
|
def test_create_own_redirect_for_old_apache_version(self):
|
2020-03-23 19:49:52 -04:00
|
|
|
self.config.parser.modules["rewrite_module"] = None
|
2015-12-02 20:40:12 -05:00
|
|
|
self.config.get_version = mock.Mock(return_value=(2, 2))
|
2015-07-24 06:22:35 -04:00
|
|
|
# For full testing... give names...
|
|
|
|
|
self.vh_truth[1].name = "default.com"
|
2020-04-13 13:41:39 -04:00
|
|
|
self.vh_truth[1].aliases = {"yes.default.com"}
|
2015-07-24 06:22:35 -04:00
|
|
|
|
2016-01-14 06:25:15 -05:00
|
|
|
# pylint: disable=protected-access
|
|
|
|
|
self.config._enable_redirect(self.vh_truth[1], "")
|
2023-02-16 00:02:02 -05:00
|
|
|
assert len(self.config.vhosts) == 13
|
2015-07-24 06:22:35 -04:00
|
|
|
|
2016-07-01 17:06:16 -04:00
|
|
|
def test_sift_rewrite_rule(self):
|
2016-01-11 14:55:55 -05:00
|
|
|
# pylint: disable=protected-access
|
|
|
|
|
small_quoted_target = "RewriteRule ^ \"http://\""
|
2023-02-16 00:02:02 -05:00
|
|
|
assert self.config._sift_rewrite_rule(small_quoted_target) is False
|
2016-01-11 14:55:55 -05:00
|
|
|
|
|
|
|
|
https_target = "RewriteRule ^ https://satoshi"
|
2023-02-16 00:02:02 -05:00
|
|
|
assert self.config._sift_rewrite_rule(https_target) is True
|
2016-01-11 14:55:55 -05:00
|
|
|
|
2016-01-11 15:59:19 -05:00
|
|
|
normal_target = "RewriteRule ^/(.*) http://www.a.com:1234/$1 [L,R]"
|
2023-02-16 00:02:02 -05:00
|
|
|
assert self.config._sift_rewrite_rule(normal_target) is False
|
2016-07-01 17:06:16 -04:00
|
|
|
|
|
|
|
|
not_rewriterule = "NotRewriteRule ^ ..."
|
2023-02-16 00:02:02 -05:00
|
|
|
assert self.config._sift_rewrite_rule(not_rewriterule) is False
|
2015-12-02 20:40:12 -05:00
|
|
|
|
2018-01-10 23:14:56 -05:00
|
|
|
def get_key_and_achalls(self):
|
2015-07-24 18:47:38 -04:00
|
|
|
"""Return testing achallenges."""
|
2015-08-11 16:22:03 -04:00
|
|
|
account_key = self.rsa512jwk
|
2015-11-07 13:10:56 -05:00
|
|
|
achall1 = achallenges.KeyAuthorizationAnnotatedChallenge(
|
2015-07-24 06:22:35 -04:00
|
|
|
challb=acme_util.chall_to_challb(
|
2019-10-31 13:17:29 -04:00
|
|
|
challenges.HTTP01(
|
2017-02-24 21:21:21 -05:00
|
|
|
token=b"jIq_Xy1mXGN37tb4L6Xj_es58fW571ZNyXekdZzhh7Q"),
|
2015-07-24 06:22:35 -04:00
|
|
|
"pending"),
|
2015-08-11 16:22:03 -04:00
|
|
|
domain="encryption-example.demo", account_key=account_key)
|
2015-11-07 13:10:56 -05:00
|
|
|
achall2 = achallenges.KeyAuthorizationAnnotatedChallenge(
|
2015-07-24 06:22:35 -04:00
|
|
|
challb=acme_util.chall_to_challb(
|
2019-10-31 13:17:29 -04:00
|
|
|
challenges.HTTP01(
|
2017-02-24 21:21:21 -05:00
|
|
|
token=b"uqnaPzxtrndteOqtrXb0Asl5gOJfWAnnx6QJyvcmlDU"),
|
2015-07-24 06:22:35 -04:00
|
|
|
"pending"),
|
2016-04-13 19:30:57 -04:00
|
|
|
domain="certbot.demo", account_key=account_key)
|
2018-01-10 23:14:56 -05:00
|
|
|
achall3 = achallenges.KeyAuthorizationAnnotatedChallenge(
|
|
|
|
|
challb=acme_util.chall_to_challb(
|
|
|
|
|
challenges.HTTP01(token=(b'x' * 16)), "pending"),
|
|
|
|
|
domain="example.org", account_key=account_key)
|
2015-07-24 06:22:35 -04:00
|
|
|
|
2018-01-10 23:14:56 -05:00
|
|
|
return account_key, (achall1, achall2, achall3)
|
2015-07-24 06:22:35 -04:00
|
|
|
|
Distribution specific override functionality based on class inheritance (#5202)
Class inheritance based approach to distro specific overrides.
How it works:
The certbot-apache plugin entrypoint has been changed to entrypoint.ENTRYPOINT which is a variable containing appropriate override class for system, if available.
Override classes register themselves using decorator override.register() which takes a list of distribution fingerprints (ID & LIKE variables in /etc/os-release, or platform.linux_distribution() as a fallback). These end up as keys in dict override.OVERRIDE_CLASSES and values for the keys are references to the class that called the decorator, hence allowing self-registration of override classes when they are imported. The only file importing these override classes is entrypoint.py, so adding new override classes would need only one import in addition to the actual override class file.
Generic changes:
Parser initialization has been moved to separate class method, allowing easy override where needed.
Cleaned up configurator.py a bit, and moved some helper functions to newly created apache_util.py
Split Debian specific code from configurator.py to debian_override.py
Changed define_cmd to apache_cmd because the parameters are for every distribution supporting this behavior, and we're able to use the value to build the additional configuration dump commands.
Moved add_parser_mod() from configurator to parser add_mod()
Added two new configuration dump parsing methods to update_runtime_variables() in parser: update_includes() and update_modules().
Changed init_modules() in parser to accommodate the changes above. (ie. don't throw existing self.modules out).
Moved OS based constants to their respective override classes.
Refactored configurator class discovery in tests to help easier test case creation using distribution based override configurator class.
tests.util.get_apache_configurator() now takes keyword argument os_info which is string of the desired mock OS fingerprint response that's used for picking the right override class.
This PR includes two major generic additions that should vastly improve our parsing accuracy and quality:
Includes are parsed from config dump from httpd binary. This is mandatory for some distributions (Like OpenSUSE) to get visibility over the whole configuration tree because of Include statements passed on in command line, and not via root httpd.conf file.
Modules are parsed from config dump from httpd binary. This lets us jump into correct IfModule directives if for some reason we have missed the module availability (because of one being included on command line or such).
Distribution specific changes
Because of the generic changes, there are two distributions (or distribution families) that do not provide such functionality, so it had to be overridden in their respective override files. These distributions are:
CentOS, because it deliberately limits httpd binary stdout using SELinux as a feature. We are doing opportunistic config dumps here however, in case SELinux enforcing is off.
Gentoo, because it does not provide a way to invoke httpd with command line parsed from its specific configuration file. Gentoo relies heavily on Define statements that are passed over from APACHE2_OPTS variable /etc/conf.d/apache2 file and most of the configuration in root Apache configuration are dependent on these values.
Debian
Moved the Debian specific parts from configurator.py to Debian specific override.
CentOS
Parsing of /etc/sysconfig/httpd file for additional Define statements. This could hold other parameters too, but parsing everything off it would require a full Apache lexer. For CLI parameters, I think Defines are the most common ones. This is done in addition of opportunistic parsing of httpd binary config dump.
Added CentOS default Apache configuration tree for realistic test cases.
Gentoo
Parsing Defines from /etc/conf.d/apache2 variable APACHE2_OPTS, which holds additional Define statements to enable certain functionalities, enabling parts of the configuration in the Apache2 DOM. This is done instead of trying to parse httpd binary configuration dumps.
Added default Apache configuration from Gentoo to testdata, including /etc/conf.d/apache2 file for realistic test cases.
* Distribution specific override functionality based on class inheritance
* Need to patch get_systemd_os_like to as travis has proper os-release
* Added pydoc
* Move parser initialization to a method and fix Python 3 __new__ errors
* Parser changes to parse HTTPD config
* Try to get modules and includes from httpd process for better visibility over the configuration
* Had to disable duplicate-code because of test setup (PyCQA/pylint/issues/214)
* CentOS tests and linter fixes
* Gentoo override, tests and linter fixes
* Mock the process call in all the tests that require it
* Fix CentOS test mock
* Restore reseting modules list functionality for cleanup
* Move OS fingerprinting and constant mocks to parent class
* Fixes requested in review
* New entrypoint structure and started moving OS constants to override classes
* OS constants move continued, test and linter fixes
* Removed dead code
* Apache compatibility test changest to reflect OS constant restructure
* Test fix
* Requested changes
* Moved Debian specific tests to own test file
* Removed decorator based override class registration in favor of entrypoint dict
* Fix for update_includes for some versions of Augeas
* Take fedora fix into account in tests
* Review fixes
2017-12-04 14:49:18 -05:00
|
|
|
def test_enable_site_nondebian(self):
|
|
|
|
|
inc_path = "/path/to/wherever"
|
|
|
|
|
vhost = self.vh_truth[0]
|
|
|
|
|
vhost.enabled = False
|
|
|
|
|
vhost.filep = inc_path
|
2023-02-16 00:02:02 -05:00
|
|
|
assert self.config.parser.find_dir("Include", inc_path) == []
|
|
|
|
|
assert os.path.dirname(inc_path) not in self.config.parser.existing_paths
|
Distribution specific override functionality based on class inheritance (#5202)
Class inheritance based approach to distro specific overrides.
How it works:
The certbot-apache plugin entrypoint has been changed to entrypoint.ENTRYPOINT which is a variable containing appropriate override class for system, if available.
Override classes register themselves using decorator override.register() which takes a list of distribution fingerprints (ID & LIKE variables in /etc/os-release, or platform.linux_distribution() as a fallback). These end up as keys in dict override.OVERRIDE_CLASSES and values for the keys are references to the class that called the decorator, hence allowing self-registration of override classes when they are imported. The only file importing these override classes is entrypoint.py, so adding new override classes would need only one import in addition to the actual override class file.
Generic changes:
Parser initialization has been moved to separate class method, allowing easy override where needed.
Cleaned up configurator.py a bit, and moved some helper functions to newly created apache_util.py
Split Debian specific code from configurator.py to debian_override.py
Changed define_cmd to apache_cmd because the parameters are for every distribution supporting this behavior, and we're able to use the value to build the additional configuration dump commands.
Moved add_parser_mod() from configurator to parser add_mod()
Added two new configuration dump parsing methods to update_runtime_variables() in parser: update_includes() and update_modules().
Changed init_modules() in parser to accommodate the changes above. (ie. don't throw existing self.modules out).
Moved OS based constants to their respective override classes.
Refactored configurator class discovery in tests to help easier test case creation using distribution based override configurator class.
tests.util.get_apache_configurator() now takes keyword argument os_info which is string of the desired mock OS fingerprint response that's used for picking the right override class.
This PR includes two major generic additions that should vastly improve our parsing accuracy and quality:
Includes are parsed from config dump from httpd binary. This is mandatory for some distributions (Like OpenSUSE) to get visibility over the whole configuration tree because of Include statements passed on in command line, and not via root httpd.conf file.
Modules are parsed from config dump from httpd binary. This lets us jump into correct IfModule directives if for some reason we have missed the module availability (because of one being included on command line or such).
Distribution specific changes
Because of the generic changes, there are two distributions (or distribution families) that do not provide such functionality, so it had to be overridden in their respective override files. These distributions are:
CentOS, because it deliberately limits httpd binary stdout using SELinux as a feature. We are doing opportunistic config dumps here however, in case SELinux enforcing is off.
Gentoo, because it does not provide a way to invoke httpd with command line parsed from its specific configuration file. Gentoo relies heavily on Define statements that are passed over from APACHE2_OPTS variable /etc/conf.d/apache2 file and most of the configuration in root Apache configuration are dependent on these values.
Debian
Moved the Debian specific parts from configurator.py to Debian specific override.
CentOS
Parsing of /etc/sysconfig/httpd file for additional Define statements. This could hold other parameters too, but parsing everything off it would require a full Apache lexer. For CLI parameters, I think Defines are the most common ones. This is done in addition of opportunistic parsing of httpd binary config dump.
Added CentOS default Apache configuration tree for realistic test cases.
Gentoo
Parsing Defines from /etc/conf.d/apache2 variable APACHE2_OPTS, which holds additional Define statements to enable certain functionalities, enabling parts of the configuration in the Apache2 DOM. This is done instead of trying to parse httpd binary configuration dumps.
Added default Apache configuration from Gentoo to testdata, including /etc/conf.d/apache2 file for realistic test cases.
* Distribution specific override functionality based on class inheritance
* Need to patch get_systemd_os_like to as travis has proper os-release
* Added pydoc
* Move parser initialization to a method and fix Python 3 __new__ errors
* Parser changes to parse HTTPD config
* Try to get modules and includes from httpd process for better visibility over the configuration
* Had to disable duplicate-code because of test setup (PyCQA/pylint/issues/214)
* CentOS tests and linter fixes
* Gentoo override, tests and linter fixes
* Mock the process call in all the tests that require it
* Fix CentOS test mock
* Restore reseting modules list functionality for cleanup
* Move OS fingerprinting and constant mocks to parent class
* Fixes requested in review
* New entrypoint structure and started moving OS constants to override classes
* OS constants move continued, test and linter fixes
* Removed dead code
* Apache compatibility test changest to reflect OS constant restructure
* Test fix
* Requested changes
* Moved Debian specific tests to own test file
* Removed decorator based override class registration in favor of entrypoint dict
* Fix for update_includes for some versions of Augeas
* Take fedora fix into account in tests
* Review fixes
2017-12-04 14:49:18 -05:00
|
|
|
self.config.enable_site(vhost)
|
2023-02-16 00:02:02 -05:00
|
|
|
assert len(self.config.parser.find_dir("Include", inc_path)) >= 1
|
|
|
|
|
assert os.path.dirname(inc_path) in self.config.parser.existing_paths
|
|
|
|
|
assert os.path.basename(inc_path) in self.config.parser.existing_paths[
|
|
|
|
|
os.path.dirname(inc_path)]
|
Distribution specific override functionality based on class inheritance (#5202)
Class inheritance based approach to distro specific overrides.
How it works:
The certbot-apache plugin entrypoint has been changed to entrypoint.ENTRYPOINT which is a variable containing appropriate override class for system, if available.
Override classes register themselves using decorator override.register() which takes a list of distribution fingerprints (ID & LIKE variables in /etc/os-release, or platform.linux_distribution() as a fallback). These end up as keys in dict override.OVERRIDE_CLASSES and values for the keys are references to the class that called the decorator, hence allowing self-registration of override classes when they are imported. The only file importing these override classes is entrypoint.py, so adding new override classes would need only one import in addition to the actual override class file.
Generic changes:
Parser initialization has been moved to separate class method, allowing easy override where needed.
Cleaned up configurator.py a bit, and moved some helper functions to newly created apache_util.py
Split Debian specific code from configurator.py to debian_override.py
Changed define_cmd to apache_cmd because the parameters are for every distribution supporting this behavior, and we're able to use the value to build the additional configuration dump commands.
Moved add_parser_mod() from configurator to parser add_mod()
Added two new configuration dump parsing methods to update_runtime_variables() in parser: update_includes() and update_modules().
Changed init_modules() in parser to accommodate the changes above. (ie. don't throw existing self.modules out).
Moved OS based constants to their respective override classes.
Refactored configurator class discovery in tests to help easier test case creation using distribution based override configurator class.
tests.util.get_apache_configurator() now takes keyword argument os_info which is string of the desired mock OS fingerprint response that's used for picking the right override class.
This PR includes two major generic additions that should vastly improve our parsing accuracy and quality:
Includes are parsed from config dump from httpd binary. This is mandatory for some distributions (Like OpenSUSE) to get visibility over the whole configuration tree because of Include statements passed on in command line, and not via root httpd.conf file.
Modules are parsed from config dump from httpd binary. This lets us jump into correct IfModule directives if for some reason we have missed the module availability (because of one being included on command line or such).
Distribution specific changes
Because of the generic changes, there are two distributions (or distribution families) that do not provide such functionality, so it had to be overridden in their respective override files. These distributions are:
CentOS, because it deliberately limits httpd binary stdout using SELinux as a feature. We are doing opportunistic config dumps here however, in case SELinux enforcing is off.
Gentoo, because it does not provide a way to invoke httpd with command line parsed from its specific configuration file. Gentoo relies heavily on Define statements that are passed over from APACHE2_OPTS variable /etc/conf.d/apache2 file and most of the configuration in root Apache configuration are dependent on these values.
Debian
Moved the Debian specific parts from configurator.py to Debian specific override.
CentOS
Parsing of /etc/sysconfig/httpd file for additional Define statements. This could hold other parameters too, but parsing everything off it would require a full Apache lexer. For CLI parameters, I think Defines are the most common ones. This is done in addition of opportunistic parsing of httpd binary config dump.
Added CentOS default Apache configuration tree for realistic test cases.
Gentoo
Parsing Defines from /etc/conf.d/apache2 variable APACHE2_OPTS, which holds additional Define statements to enable certain functionalities, enabling parts of the configuration in the Apache2 DOM. This is done instead of trying to parse httpd binary configuration dumps.
Added default Apache configuration from Gentoo to testdata, including /etc/conf.d/apache2 file for realistic test cases.
* Distribution specific override functionality based on class inheritance
* Need to patch get_systemd_os_like to as travis has proper os-release
* Added pydoc
* Move parser initialization to a method and fix Python 3 __new__ errors
* Parser changes to parse HTTPD config
* Try to get modules and includes from httpd process for better visibility over the configuration
* Had to disable duplicate-code because of test setup (PyCQA/pylint/issues/214)
* CentOS tests and linter fixes
* Gentoo override, tests and linter fixes
* Mock the process call in all the tests that require it
* Fix CentOS test mock
* Restore reseting modules list functionality for cleanup
* Move OS fingerprinting and constant mocks to parent class
* Fixes requested in review
* New entrypoint structure and started moving OS constants to override classes
* OS constants move continued, test and linter fixes
* Removed dead code
* Apache compatibility test changest to reflect OS constant restructure
* Test fix
* Requested changes
* Moved Debian specific tests to own test file
* Removed decorator based override class registration in favor of entrypoint dict
* Fix for update_includes for some versions of Augeas
* Take fedora fix into account in tests
* Review fixes
2017-12-04 14:49:18 -05:00
|
|
|
|
Command-line UX overhaul (#8852)
Streamline and reorganize Certbot's CLI output.
This change is a substantial command-line UX overhaul,
based on previous user research. The main goal was to streamline
and clarify output. To see more verbose output, use the -v or -vv flags.
---
* nginx,apache: CLI logging changes
- Add "Successfully deployed ..." message using display_util
- Remove IReporter usage and replace with display_util
- Standardize "... could not find a VirtualHost ..." error
This changes also bumps the version of certbot required by certbot-nginx
and certbot-apache to take use of the new display_util function.
* fix certbot_compatibility_test
since the http plugins now require IDisplay, we need to inject it
* fix dependency version on certbot
* use better asserts
* try fix oldest deps
because certbot 1.10.0 depends on acme>=1.8.0, we need to use
acme==1.8.0 in the -oldest tests
* cli: redesign output of new certificate reporting
Changes the output of run, certonly and certonly --csr. No longer uses
IReporter.
* cli: redesign output of failed authz reporting
* fix problem sorting to be stable between py2 & 3
* add some catch-all error text
* cli: dont use IReporter for EFF donation prompt
* add per-authenticator hints
* pass achalls to auth_hint, write some tests
* exclude static auth hints from coverage
* dont call auth_hint unless derived from .Plugin
* dns fallback hint: dont assume --dns-blah works
--dns-blah won't work for third-party plugins, they need to be specified
using --authenticator dns-blah.
* add code comments about the auth_hint interface
* renew: don't restart the installer for dry-runs
Prevents Certbot from superfluously invoking the installer restart
during dry-run renewals. (This does not affect authenticator restarts).
Additionally removes some CLI output that was reporting the fullchain
path of the renewed certificate.
* update CHANGELOG.md
* cli: redesign output when cert installation failed
- Display a message when certificate installation begins.
- Don't use IReporter, just log errors immediately if restart/rollback
fails.
- Prompt the user with a command to retry the installation process once
they have fixed any underlying problems.
* vary by preconfigured_renewal
and move expiry date to be above the renewal advice
* update code comment
Co-authored-by: ohemorange <ebportnoy@gmail.com>
* update code comment
Co-authored-by: ohemorange <ebportnoy@gmail.com>
* fix lint
* derve cert name from cert_path, if possible
* fix type annotation
* text change in nginx hint
Co-authored-by: ohemorange <ebportnoy@gmail.com>
* print message when restarting server after renewal
* log: print "advice" when exiting with an error
When running in non-quiet mode.
* try fix -oldest lock_test.py
* fix docstring
* s/Restarting/Reloading/ when notifying the user
* fix test name
Co-authored-by: ohemorange <ebportnoy@gmail.com>
* type annotations
* s/using the {} plugin/installer: {}/
* copy: avoid "plugin" where possible
* link to user guide#automated-renewals
when not running with --preconfigured-renewal
* cli: reduce default logging verbosity
* fix lock_test: -vv is needed to see logger.debug
* Change comment in log.py to match the change to default verbosity
* Audit and adjust logging levels in apache module
* Audit and adjust logging levels in nginx module
* Audit, adjust logging levels, and improve logging calls in certbot module
* Fix tests to mock correct methods and classes
* typo in non-preconfigured-renewal message
Co-authored-by: ohemorange <ebportnoy@gmail.com>
* fix test
* revert acme version bump
* catch up to python3 changes
* Revert "revert acme version bump"
This reverts commit fa83d6a51cf8d0e7e17da53c6b751ad12945d0cf.
* Change ocsp check error to warning since it's non-fatal
* Update storage_test in parallel with last change
* get rid of leading newline on "Deploying [...]"
* shrink renewal and installation success messages
* print logfile rather than logdir in exit handler
* Decrease logging level to info for idempotent operation where enhancement is already set
* Display cert not yet due for renewal message when renewing and no other action will be taken, and change cert to certificate
* also write to logger so it goes in the log file
* Don't double write to log file; fix main test
* cli: remove trailing newline on new cert reporting
* ignore type error
* revert accidental changes to dependencies
* Pass tests in any timezone by using utcfromtimestamp
* Add changelog entry
* fix nits
* Improve wording of try again message
* minor wording change to changelog
* hooks: send hook stdout to CLI stdout
includes both --manual and --{pre,post,renew} hooks
* update docstrings and remove TODO
* add a pending deprecation on execute_command
* add test coverage for both
* update deprecation text
Co-authored-by: ohemorange <ebportnoy@gmail.com>
Co-authored-by: Alex Zorin <alex@zorin.id.au>
Co-authored-by: alexzorin <alex@zor.io>
2021-05-24 20:47:39 -04:00
|
|
|
@mock.patch('certbot_apache._internal.configurator.display_util.notify')
|
|
|
|
|
def test_deploy_cert_not_parsed_path(self, unused_mock_notify):
|
Distribution specific override functionality based on class inheritance (#5202)
Class inheritance based approach to distro specific overrides.
How it works:
The certbot-apache plugin entrypoint has been changed to entrypoint.ENTRYPOINT which is a variable containing appropriate override class for system, if available.
Override classes register themselves using decorator override.register() which takes a list of distribution fingerprints (ID & LIKE variables in /etc/os-release, or platform.linux_distribution() as a fallback). These end up as keys in dict override.OVERRIDE_CLASSES and values for the keys are references to the class that called the decorator, hence allowing self-registration of override classes when they are imported. The only file importing these override classes is entrypoint.py, so adding new override classes would need only one import in addition to the actual override class file.
Generic changes:
Parser initialization has been moved to separate class method, allowing easy override where needed.
Cleaned up configurator.py a bit, and moved some helper functions to newly created apache_util.py
Split Debian specific code from configurator.py to debian_override.py
Changed define_cmd to apache_cmd because the parameters are for every distribution supporting this behavior, and we're able to use the value to build the additional configuration dump commands.
Moved add_parser_mod() from configurator to parser add_mod()
Added two new configuration dump parsing methods to update_runtime_variables() in parser: update_includes() and update_modules().
Changed init_modules() in parser to accommodate the changes above. (ie. don't throw existing self.modules out).
Moved OS based constants to their respective override classes.
Refactored configurator class discovery in tests to help easier test case creation using distribution based override configurator class.
tests.util.get_apache_configurator() now takes keyword argument os_info which is string of the desired mock OS fingerprint response that's used for picking the right override class.
This PR includes two major generic additions that should vastly improve our parsing accuracy and quality:
Includes are parsed from config dump from httpd binary. This is mandatory for some distributions (Like OpenSUSE) to get visibility over the whole configuration tree because of Include statements passed on in command line, and not via root httpd.conf file.
Modules are parsed from config dump from httpd binary. This lets us jump into correct IfModule directives if for some reason we have missed the module availability (because of one being included on command line or such).
Distribution specific changes
Because of the generic changes, there are two distributions (or distribution families) that do not provide such functionality, so it had to be overridden in their respective override files. These distributions are:
CentOS, because it deliberately limits httpd binary stdout using SELinux as a feature. We are doing opportunistic config dumps here however, in case SELinux enforcing is off.
Gentoo, because it does not provide a way to invoke httpd with command line parsed from its specific configuration file. Gentoo relies heavily on Define statements that are passed over from APACHE2_OPTS variable /etc/conf.d/apache2 file and most of the configuration in root Apache configuration are dependent on these values.
Debian
Moved the Debian specific parts from configurator.py to Debian specific override.
CentOS
Parsing of /etc/sysconfig/httpd file for additional Define statements. This could hold other parameters too, but parsing everything off it would require a full Apache lexer. For CLI parameters, I think Defines are the most common ones. This is done in addition of opportunistic parsing of httpd binary config dump.
Added CentOS default Apache configuration tree for realistic test cases.
Gentoo
Parsing Defines from /etc/conf.d/apache2 variable APACHE2_OPTS, which holds additional Define statements to enable certain functionalities, enabling parts of the configuration in the Apache2 DOM. This is done instead of trying to parse httpd binary configuration dumps.
Added default Apache configuration from Gentoo to testdata, including /etc/conf.d/apache2 file for realistic test cases.
* Distribution specific override functionality based on class inheritance
* Need to patch get_systemd_os_like to as travis has proper os-release
* Added pydoc
* Move parser initialization to a method and fix Python 3 __new__ errors
* Parser changes to parse HTTPD config
* Try to get modules and includes from httpd process for better visibility over the configuration
* Had to disable duplicate-code because of test setup (PyCQA/pylint/issues/214)
* CentOS tests and linter fixes
* Gentoo override, tests and linter fixes
* Mock the process call in all the tests that require it
* Fix CentOS test mock
* Restore reseting modules list functionality for cleanup
* Move OS fingerprinting and constant mocks to parent class
* Fixes requested in review
* New entrypoint structure and started moving OS constants to override classes
* OS constants move continued, test and linter fixes
* Removed dead code
* Apache compatibility test changest to reflect OS constant restructure
* Test fix
* Requested changes
* Moved Debian specific tests to own test file
* Removed decorator based override class registration in favor of entrypoint dict
* Fix for update_includes for some versions of Augeas
* Take fedora fix into account in tests
* Review fixes
2017-12-04 14:49:18 -05:00
|
|
|
# Make sure that we add include to root config for vhosts when
|
|
|
|
|
# handle-sites is false
|
2020-03-23 19:49:52 -04:00
|
|
|
self.config.parser.modules["ssl_module"] = None
|
|
|
|
|
self.config.parser.modules["mod_ssl.c"] = None
|
|
|
|
|
self.config.parser.modules["socache_shmcb_module"] = None
|
2019-07-18 17:31:39 -04:00
|
|
|
tmp_path = filesystem.realpath(tempfile.mkdtemp("vhostroot"))
|
2019-06-20 13:52:43 -04:00
|
|
|
filesystem.chmod(tmp_path, 0o755)
|
2019-11-25 12:44:40 -05:00
|
|
|
mock_p = "certbot_apache._internal.configurator.ApacheConfigurator._get_ssl_vhost_path"
|
|
|
|
|
mock_a = "certbot_apache._internal.parser.ApacheParser.add_include"
|
Distribution specific override functionality based on class inheritance (#5202)
Class inheritance based approach to distro specific overrides.
How it works:
The certbot-apache plugin entrypoint has been changed to entrypoint.ENTRYPOINT which is a variable containing appropriate override class for system, if available.
Override classes register themselves using decorator override.register() which takes a list of distribution fingerprints (ID & LIKE variables in /etc/os-release, or platform.linux_distribution() as a fallback). These end up as keys in dict override.OVERRIDE_CLASSES and values for the keys are references to the class that called the decorator, hence allowing self-registration of override classes when they are imported. The only file importing these override classes is entrypoint.py, so adding new override classes would need only one import in addition to the actual override class file.
Generic changes:
Parser initialization has been moved to separate class method, allowing easy override where needed.
Cleaned up configurator.py a bit, and moved some helper functions to newly created apache_util.py
Split Debian specific code from configurator.py to debian_override.py
Changed define_cmd to apache_cmd because the parameters are for every distribution supporting this behavior, and we're able to use the value to build the additional configuration dump commands.
Moved add_parser_mod() from configurator to parser add_mod()
Added two new configuration dump parsing methods to update_runtime_variables() in parser: update_includes() and update_modules().
Changed init_modules() in parser to accommodate the changes above. (ie. don't throw existing self.modules out).
Moved OS based constants to their respective override classes.
Refactored configurator class discovery in tests to help easier test case creation using distribution based override configurator class.
tests.util.get_apache_configurator() now takes keyword argument os_info which is string of the desired mock OS fingerprint response that's used for picking the right override class.
This PR includes two major generic additions that should vastly improve our parsing accuracy and quality:
Includes are parsed from config dump from httpd binary. This is mandatory for some distributions (Like OpenSUSE) to get visibility over the whole configuration tree because of Include statements passed on in command line, and not via root httpd.conf file.
Modules are parsed from config dump from httpd binary. This lets us jump into correct IfModule directives if for some reason we have missed the module availability (because of one being included on command line or such).
Distribution specific changes
Because of the generic changes, there are two distributions (or distribution families) that do not provide such functionality, so it had to be overridden in their respective override files. These distributions are:
CentOS, because it deliberately limits httpd binary stdout using SELinux as a feature. We are doing opportunistic config dumps here however, in case SELinux enforcing is off.
Gentoo, because it does not provide a way to invoke httpd with command line parsed from its specific configuration file. Gentoo relies heavily on Define statements that are passed over from APACHE2_OPTS variable /etc/conf.d/apache2 file and most of the configuration in root Apache configuration are dependent on these values.
Debian
Moved the Debian specific parts from configurator.py to Debian specific override.
CentOS
Parsing of /etc/sysconfig/httpd file for additional Define statements. This could hold other parameters too, but parsing everything off it would require a full Apache lexer. For CLI parameters, I think Defines are the most common ones. This is done in addition of opportunistic parsing of httpd binary config dump.
Added CentOS default Apache configuration tree for realistic test cases.
Gentoo
Parsing Defines from /etc/conf.d/apache2 variable APACHE2_OPTS, which holds additional Define statements to enable certain functionalities, enabling parts of the configuration in the Apache2 DOM. This is done instead of trying to parse httpd binary configuration dumps.
Added default Apache configuration from Gentoo to testdata, including /etc/conf.d/apache2 file for realistic test cases.
* Distribution specific override functionality based on class inheritance
* Need to patch get_systemd_os_like to as travis has proper os-release
* Added pydoc
* Move parser initialization to a method and fix Python 3 __new__ errors
* Parser changes to parse HTTPD config
* Try to get modules and includes from httpd process for better visibility over the configuration
* Had to disable duplicate-code because of test setup (PyCQA/pylint/issues/214)
* CentOS tests and linter fixes
* Gentoo override, tests and linter fixes
* Mock the process call in all the tests that require it
* Fix CentOS test mock
* Restore reseting modules list functionality for cleanup
* Move OS fingerprinting and constant mocks to parent class
* Fixes requested in review
* New entrypoint structure and started moving OS constants to override classes
* OS constants move continued, test and linter fixes
* Removed dead code
* Apache compatibility test changest to reflect OS constant restructure
* Test fix
* Requested changes
* Moved Debian specific tests to own test file
* Removed decorator based override class registration in favor of entrypoint dict
* Fix for update_includes for some versions of Augeas
* Take fedora fix into account in tests
* Review fixes
2017-12-04 14:49:18 -05:00
|
|
|
|
|
|
|
|
with mock.patch(mock_p) as mock_path:
|
|
|
|
|
mock_path.return_value = os.path.join(tmp_path, "whatever.conf")
|
|
|
|
|
with mock.patch(mock_a) as mock_add:
|
|
|
|
|
self.config.deploy_cert(
|
|
|
|
|
"encryption-example.demo",
|
|
|
|
|
"example/cert.pem", "example/key.pem",
|
|
|
|
|
"example/cert_chain.pem")
|
|
|
|
|
# Test that we actually called add_include
|
2023-02-16 00:02:02 -05:00
|
|
|
assert mock_add.called is True
|
Distribution specific override functionality based on class inheritance (#5202)
Class inheritance based approach to distro specific overrides.
How it works:
The certbot-apache plugin entrypoint has been changed to entrypoint.ENTRYPOINT which is a variable containing appropriate override class for system, if available.
Override classes register themselves using decorator override.register() which takes a list of distribution fingerprints (ID & LIKE variables in /etc/os-release, or platform.linux_distribution() as a fallback). These end up as keys in dict override.OVERRIDE_CLASSES and values for the keys are references to the class that called the decorator, hence allowing self-registration of override classes when they are imported. The only file importing these override classes is entrypoint.py, so adding new override classes would need only one import in addition to the actual override class file.
Generic changes:
Parser initialization has been moved to separate class method, allowing easy override where needed.
Cleaned up configurator.py a bit, and moved some helper functions to newly created apache_util.py
Split Debian specific code from configurator.py to debian_override.py
Changed define_cmd to apache_cmd because the parameters are for every distribution supporting this behavior, and we're able to use the value to build the additional configuration dump commands.
Moved add_parser_mod() from configurator to parser add_mod()
Added two new configuration dump parsing methods to update_runtime_variables() in parser: update_includes() and update_modules().
Changed init_modules() in parser to accommodate the changes above. (ie. don't throw existing self.modules out).
Moved OS based constants to their respective override classes.
Refactored configurator class discovery in tests to help easier test case creation using distribution based override configurator class.
tests.util.get_apache_configurator() now takes keyword argument os_info which is string of the desired mock OS fingerprint response that's used for picking the right override class.
This PR includes two major generic additions that should vastly improve our parsing accuracy and quality:
Includes are parsed from config dump from httpd binary. This is mandatory for some distributions (Like OpenSUSE) to get visibility over the whole configuration tree because of Include statements passed on in command line, and not via root httpd.conf file.
Modules are parsed from config dump from httpd binary. This lets us jump into correct IfModule directives if for some reason we have missed the module availability (because of one being included on command line or such).
Distribution specific changes
Because of the generic changes, there are two distributions (or distribution families) that do not provide such functionality, so it had to be overridden in their respective override files. These distributions are:
CentOS, because it deliberately limits httpd binary stdout using SELinux as a feature. We are doing opportunistic config dumps here however, in case SELinux enforcing is off.
Gentoo, because it does not provide a way to invoke httpd with command line parsed from its specific configuration file. Gentoo relies heavily on Define statements that are passed over from APACHE2_OPTS variable /etc/conf.d/apache2 file and most of the configuration in root Apache configuration are dependent on these values.
Debian
Moved the Debian specific parts from configurator.py to Debian specific override.
CentOS
Parsing of /etc/sysconfig/httpd file for additional Define statements. This could hold other parameters too, but parsing everything off it would require a full Apache lexer. For CLI parameters, I think Defines are the most common ones. This is done in addition of opportunistic parsing of httpd binary config dump.
Added CentOS default Apache configuration tree for realistic test cases.
Gentoo
Parsing Defines from /etc/conf.d/apache2 variable APACHE2_OPTS, which holds additional Define statements to enable certain functionalities, enabling parts of the configuration in the Apache2 DOM. This is done instead of trying to parse httpd binary configuration dumps.
Added default Apache configuration from Gentoo to testdata, including /etc/conf.d/apache2 file for realistic test cases.
* Distribution specific override functionality based on class inheritance
* Need to patch get_systemd_os_like to as travis has proper os-release
* Added pydoc
* Move parser initialization to a method and fix Python 3 __new__ errors
* Parser changes to parse HTTPD config
* Try to get modules and includes from httpd process for better visibility over the configuration
* Had to disable duplicate-code because of test setup (PyCQA/pylint/issues/214)
* CentOS tests and linter fixes
* Gentoo override, tests and linter fixes
* Mock the process call in all the tests that require it
* Fix CentOS test mock
* Restore reseting modules list functionality for cleanup
* Move OS fingerprinting and constant mocks to parent class
* Fixes requested in review
* New entrypoint structure and started moving OS constants to override classes
* OS constants move continued, test and linter fixes
* Removed dead code
* Apache compatibility test changest to reflect OS constant restructure
* Test fix
* Requested changes
* Moved Debian specific tests to own test file
* Removed decorator based override class registration in favor of entrypoint dict
* Fix for update_includes for some versions of Augeas
* Take fedora fix into account in tests
* Review fixes
2017-12-04 14:49:18 -05:00
|
|
|
shutil.rmtree(tmp_path)
|
|
|
|
|
|
2020-05-19 18:34:21 -04:00
|
|
|
def test_deploy_cert_no_mod_ssl(self):
|
|
|
|
|
# Create
|
|
|
|
|
ssl_vhost = self.config.make_vhost_ssl(self.vh_truth[0])
|
|
|
|
|
self.config.parser.modules["socache_shmcb_module"] = None
|
|
|
|
|
self.config.prepare_server_https = mock.Mock()
|
|
|
|
|
|
2023-02-16 00:02:02 -05:00
|
|
|
with pytest.raises(errors.MisconfigurationError):
|
|
|
|
|
self.config.deploy_cert("encryption-example.demo", "example/cert.pem", "example/key.pem",
|
2020-05-19 18:34:21 -04:00
|
|
|
"example/cert_chain.pem", "example/fullchain.pem")
|
|
|
|
|
|
2019-11-25 12:44:40 -05:00
|
|
|
@mock.patch("certbot_apache._internal.parser.ApacheParser.parsed_in_original")
|
Distribution specific override functionality based on class inheritance (#5202)
Class inheritance based approach to distro specific overrides.
How it works:
The certbot-apache plugin entrypoint has been changed to entrypoint.ENTRYPOINT which is a variable containing appropriate override class for system, if available.
Override classes register themselves using decorator override.register() which takes a list of distribution fingerprints (ID & LIKE variables in /etc/os-release, or platform.linux_distribution() as a fallback). These end up as keys in dict override.OVERRIDE_CLASSES and values for the keys are references to the class that called the decorator, hence allowing self-registration of override classes when they are imported. The only file importing these override classes is entrypoint.py, so adding new override classes would need only one import in addition to the actual override class file.
Generic changes:
Parser initialization has been moved to separate class method, allowing easy override where needed.
Cleaned up configurator.py a bit, and moved some helper functions to newly created apache_util.py
Split Debian specific code from configurator.py to debian_override.py
Changed define_cmd to apache_cmd because the parameters are for every distribution supporting this behavior, and we're able to use the value to build the additional configuration dump commands.
Moved add_parser_mod() from configurator to parser add_mod()
Added two new configuration dump parsing methods to update_runtime_variables() in parser: update_includes() and update_modules().
Changed init_modules() in parser to accommodate the changes above. (ie. don't throw existing self.modules out).
Moved OS based constants to their respective override classes.
Refactored configurator class discovery in tests to help easier test case creation using distribution based override configurator class.
tests.util.get_apache_configurator() now takes keyword argument os_info which is string of the desired mock OS fingerprint response that's used for picking the right override class.
This PR includes two major generic additions that should vastly improve our parsing accuracy and quality:
Includes are parsed from config dump from httpd binary. This is mandatory for some distributions (Like OpenSUSE) to get visibility over the whole configuration tree because of Include statements passed on in command line, and not via root httpd.conf file.
Modules are parsed from config dump from httpd binary. This lets us jump into correct IfModule directives if for some reason we have missed the module availability (because of one being included on command line or such).
Distribution specific changes
Because of the generic changes, there are two distributions (or distribution families) that do not provide such functionality, so it had to be overridden in their respective override files. These distributions are:
CentOS, because it deliberately limits httpd binary stdout using SELinux as a feature. We are doing opportunistic config dumps here however, in case SELinux enforcing is off.
Gentoo, because it does not provide a way to invoke httpd with command line parsed from its specific configuration file. Gentoo relies heavily on Define statements that are passed over from APACHE2_OPTS variable /etc/conf.d/apache2 file and most of the configuration in root Apache configuration are dependent on these values.
Debian
Moved the Debian specific parts from configurator.py to Debian specific override.
CentOS
Parsing of /etc/sysconfig/httpd file for additional Define statements. This could hold other parameters too, but parsing everything off it would require a full Apache lexer. For CLI parameters, I think Defines are the most common ones. This is done in addition of opportunistic parsing of httpd binary config dump.
Added CentOS default Apache configuration tree for realistic test cases.
Gentoo
Parsing Defines from /etc/conf.d/apache2 variable APACHE2_OPTS, which holds additional Define statements to enable certain functionalities, enabling parts of the configuration in the Apache2 DOM. This is done instead of trying to parse httpd binary configuration dumps.
Added default Apache configuration from Gentoo to testdata, including /etc/conf.d/apache2 file for realistic test cases.
* Distribution specific override functionality based on class inheritance
* Need to patch get_systemd_os_like to as travis has proper os-release
* Added pydoc
* Move parser initialization to a method and fix Python 3 __new__ errors
* Parser changes to parse HTTPD config
* Try to get modules and includes from httpd process for better visibility over the configuration
* Had to disable duplicate-code because of test setup (PyCQA/pylint/issues/214)
* CentOS tests and linter fixes
* Gentoo override, tests and linter fixes
* Mock the process call in all the tests that require it
* Fix CentOS test mock
* Restore reseting modules list functionality for cleanup
* Move OS fingerprinting and constant mocks to parent class
* Fixes requested in review
* New entrypoint structure and started moving OS constants to override classes
* OS constants move continued, test and linter fixes
* Removed dead code
* Apache compatibility test changest to reflect OS constant restructure
* Test fix
* Requested changes
* Moved Debian specific tests to own test file
* Removed decorator based override class registration in favor of entrypoint dict
* Fix for update_includes for some versions of Augeas
* Take fedora fix into account in tests
* Review fixes
2017-12-04 14:49:18 -05:00
|
|
|
def test_choose_vhost_and_servername_addition_parsed(self, mock_parsed):
|
|
|
|
|
ret_vh = self.vh_truth[8]
|
|
|
|
|
ret_vh.enabled = True
|
|
|
|
|
self.config.enable_site(ret_vh)
|
|
|
|
|
# Make sure that we return early
|
2023-02-16 00:02:02 -05:00
|
|
|
assert mock_parsed.called is False
|
Distribution specific override functionality based on class inheritance (#5202)
Class inheritance based approach to distro specific overrides.
How it works:
The certbot-apache plugin entrypoint has been changed to entrypoint.ENTRYPOINT which is a variable containing appropriate override class for system, if available.
Override classes register themselves using decorator override.register() which takes a list of distribution fingerprints (ID & LIKE variables in /etc/os-release, or platform.linux_distribution() as a fallback). These end up as keys in dict override.OVERRIDE_CLASSES and values for the keys are references to the class that called the decorator, hence allowing self-registration of override classes when they are imported. The only file importing these override classes is entrypoint.py, so adding new override classes would need only one import in addition to the actual override class file.
Generic changes:
Parser initialization has been moved to separate class method, allowing easy override where needed.
Cleaned up configurator.py a bit, and moved some helper functions to newly created apache_util.py
Split Debian specific code from configurator.py to debian_override.py
Changed define_cmd to apache_cmd because the parameters are for every distribution supporting this behavior, and we're able to use the value to build the additional configuration dump commands.
Moved add_parser_mod() from configurator to parser add_mod()
Added two new configuration dump parsing methods to update_runtime_variables() in parser: update_includes() and update_modules().
Changed init_modules() in parser to accommodate the changes above. (ie. don't throw existing self.modules out).
Moved OS based constants to their respective override classes.
Refactored configurator class discovery in tests to help easier test case creation using distribution based override configurator class.
tests.util.get_apache_configurator() now takes keyword argument os_info which is string of the desired mock OS fingerprint response that's used for picking the right override class.
This PR includes two major generic additions that should vastly improve our parsing accuracy and quality:
Includes are parsed from config dump from httpd binary. This is mandatory for some distributions (Like OpenSUSE) to get visibility over the whole configuration tree because of Include statements passed on in command line, and not via root httpd.conf file.
Modules are parsed from config dump from httpd binary. This lets us jump into correct IfModule directives if for some reason we have missed the module availability (because of one being included on command line or such).
Distribution specific changes
Because of the generic changes, there are two distributions (or distribution families) that do not provide such functionality, so it had to be overridden in their respective override files. These distributions are:
CentOS, because it deliberately limits httpd binary stdout using SELinux as a feature. We are doing opportunistic config dumps here however, in case SELinux enforcing is off.
Gentoo, because it does not provide a way to invoke httpd with command line parsed from its specific configuration file. Gentoo relies heavily on Define statements that are passed over from APACHE2_OPTS variable /etc/conf.d/apache2 file and most of the configuration in root Apache configuration are dependent on these values.
Debian
Moved the Debian specific parts from configurator.py to Debian specific override.
CentOS
Parsing of /etc/sysconfig/httpd file for additional Define statements. This could hold other parameters too, but parsing everything off it would require a full Apache lexer. For CLI parameters, I think Defines are the most common ones. This is done in addition of opportunistic parsing of httpd binary config dump.
Added CentOS default Apache configuration tree for realistic test cases.
Gentoo
Parsing Defines from /etc/conf.d/apache2 variable APACHE2_OPTS, which holds additional Define statements to enable certain functionalities, enabling parts of the configuration in the Apache2 DOM. This is done instead of trying to parse httpd binary configuration dumps.
Added default Apache configuration from Gentoo to testdata, including /etc/conf.d/apache2 file for realistic test cases.
* Distribution specific override functionality based on class inheritance
* Need to patch get_systemd_os_like to as travis has proper os-release
* Added pydoc
* Move parser initialization to a method and fix Python 3 __new__ errors
* Parser changes to parse HTTPD config
* Try to get modules and includes from httpd process for better visibility over the configuration
* Had to disable duplicate-code because of test setup (PyCQA/pylint/issues/214)
* CentOS tests and linter fixes
* Gentoo override, tests and linter fixes
* Mock the process call in all the tests that require it
* Fix CentOS test mock
* Restore reseting modules list functionality for cleanup
* Move OS fingerprinting and constant mocks to parent class
* Fixes requested in review
* New entrypoint structure and started moving OS constants to override classes
* OS constants move continued, test and linter fixes
* Removed dead code
* Apache compatibility test changest to reflect OS constant restructure
* Test fix
* Requested changes
* Moved Debian specific tests to own test file
* Removed decorator based override class registration in favor of entrypoint dict
* Fix for update_includes for some versions of Augeas
* Take fedora fix into account in tests
* Review fixes
2017-12-04 14:49:18 -05:00
|
|
|
|
|
|
|
|
def test_enable_mod_unsupported(self):
|
2023-02-16 00:02:02 -05:00
|
|
|
with pytest.raises(errors.MisconfigurationError):
|
|
|
|
|
self.config.enable_mod("whatever")
|
Distribution specific override functionality based on class inheritance (#5202)
Class inheritance based approach to distro specific overrides.
How it works:
The certbot-apache plugin entrypoint has been changed to entrypoint.ENTRYPOINT which is a variable containing appropriate override class for system, if available.
Override classes register themselves using decorator override.register() which takes a list of distribution fingerprints (ID & LIKE variables in /etc/os-release, or platform.linux_distribution() as a fallback). These end up as keys in dict override.OVERRIDE_CLASSES and values for the keys are references to the class that called the decorator, hence allowing self-registration of override classes when they are imported. The only file importing these override classes is entrypoint.py, so adding new override classes would need only one import in addition to the actual override class file.
Generic changes:
Parser initialization has been moved to separate class method, allowing easy override where needed.
Cleaned up configurator.py a bit, and moved some helper functions to newly created apache_util.py
Split Debian specific code from configurator.py to debian_override.py
Changed define_cmd to apache_cmd because the parameters are for every distribution supporting this behavior, and we're able to use the value to build the additional configuration dump commands.
Moved add_parser_mod() from configurator to parser add_mod()
Added two new configuration dump parsing methods to update_runtime_variables() in parser: update_includes() and update_modules().
Changed init_modules() in parser to accommodate the changes above. (ie. don't throw existing self.modules out).
Moved OS based constants to their respective override classes.
Refactored configurator class discovery in tests to help easier test case creation using distribution based override configurator class.
tests.util.get_apache_configurator() now takes keyword argument os_info which is string of the desired mock OS fingerprint response that's used for picking the right override class.
This PR includes two major generic additions that should vastly improve our parsing accuracy and quality:
Includes are parsed from config dump from httpd binary. This is mandatory for some distributions (Like OpenSUSE) to get visibility over the whole configuration tree because of Include statements passed on in command line, and not via root httpd.conf file.
Modules are parsed from config dump from httpd binary. This lets us jump into correct IfModule directives if for some reason we have missed the module availability (because of one being included on command line or such).
Distribution specific changes
Because of the generic changes, there are two distributions (or distribution families) that do not provide such functionality, so it had to be overridden in their respective override files. These distributions are:
CentOS, because it deliberately limits httpd binary stdout using SELinux as a feature. We are doing opportunistic config dumps here however, in case SELinux enforcing is off.
Gentoo, because it does not provide a way to invoke httpd with command line parsed from its specific configuration file. Gentoo relies heavily on Define statements that are passed over from APACHE2_OPTS variable /etc/conf.d/apache2 file and most of the configuration in root Apache configuration are dependent on these values.
Debian
Moved the Debian specific parts from configurator.py to Debian specific override.
CentOS
Parsing of /etc/sysconfig/httpd file for additional Define statements. This could hold other parameters too, but parsing everything off it would require a full Apache lexer. For CLI parameters, I think Defines are the most common ones. This is done in addition of opportunistic parsing of httpd binary config dump.
Added CentOS default Apache configuration tree for realistic test cases.
Gentoo
Parsing Defines from /etc/conf.d/apache2 variable APACHE2_OPTS, which holds additional Define statements to enable certain functionalities, enabling parts of the configuration in the Apache2 DOM. This is done instead of trying to parse httpd binary configuration dumps.
Added default Apache configuration from Gentoo to testdata, including /etc/conf.d/apache2 file for realistic test cases.
* Distribution specific override functionality based on class inheritance
* Need to patch get_systemd_os_like to as travis has proper os-release
* Added pydoc
* Move parser initialization to a method and fix Python 3 __new__ errors
* Parser changes to parse HTTPD config
* Try to get modules and includes from httpd process for better visibility over the configuration
* Had to disable duplicate-code because of test setup (PyCQA/pylint/issues/214)
* CentOS tests and linter fixes
* Gentoo override, tests and linter fixes
* Mock the process call in all the tests that require it
* Fix CentOS test mock
* Restore reseting modules list functionality for cleanup
* Move OS fingerprinting and constant mocks to parent class
* Fixes requested in review
* New entrypoint structure and started moving OS constants to override classes
* OS constants move continued, test and linter fixes
* Removed dead code
* Apache compatibility test changest to reflect OS constant restructure
* Test fix
* Requested changes
* Moved Debian specific tests to own test file
* Removed decorator based override class registration in favor of entrypoint dict
* Fix for update_includes for some versions of Augeas
* Take fedora fix into account in tests
* Review fixes
2017-12-04 14:49:18 -05:00
|
|
|
|
2018-02-28 14:31:47 -05:00
|
|
|
def test_choose_vhosts_wildcard(self):
|
|
|
|
|
# pylint: disable=protected-access
|
2019-11-25 12:44:40 -05:00
|
|
|
mock_path = "certbot_apache._internal.display_ops.select_vhost_multiple"
|
2018-02-28 14:31:47 -05:00
|
|
|
with mock.patch(mock_path) as mock_select_vhs:
|
|
|
|
|
mock_select_vhs.return_value = [self.vh_truth[3]]
|
|
|
|
|
vhs = self.config._choose_vhosts_wildcard("*.certbot.demo",
|
|
|
|
|
create_ssl=True)
|
|
|
|
|
# Check that the dialog was called with one vh: certbot.demo
|
2023-02-16 00:02:02 -05:00
|
|
|
assert mock_select_vhs.call_args[0][0][0] == self.vh_truth[3]
|
|
|
|
|
assert len(mock_select_vhs.call_args_list) == 1
|
2018-02-28 14:31:47 -05:00
|
|
|
|
|
|
|
|
# And the actual returned values
|
2023-02-16 00:02:02 -05:00
|
|
|
assert len(vhs) == 1
|
|
|
|
|
assert vhs[0].name == "certbot.demo"
|
|
|
|
|
assert vhs[0].ssl is True
|
2018-02-28 14:31:47 -05:00
|
|
|
|
2023-02-16 00:02:02 -05:00
|
|
|
assert vhs[0] != self.vh_truth[3]
|
2018-02-28 14:31:47 -05:00
|
|
|
|
2019-11-25 12:44:40 -05:00
|
|
|
@mock.patch("certbot_apache._internal.configurator.ApacheConfigurator.make_vhost_ssl")
|
2018-02-28 14:31:47 -05:00
|
|
|
def test_choose_vhosts_wildcard_no_ssl(self, mock_makessl):
|
|
|
|
|
# pylint: disable=protected-access
|
2019-11-25 12:44:40 -05:00
|
|
|
mock_path = "certbot_apache._internal.display_ops.select_vhost_multiple"
|
2018-02-28 14:31:47 -05:00
|
|
|
with mock.patch(mock_path) as mock_select_vhs:
|
|
|
|
|
mock_select_vhs.return_value = [self.vh_truth[1]]
|
|
|
|
|
vhs = self.config._choose_vhosts_wildcard("*.certbot.demo",
|
|
|
|
|
create_ssl=False)
|
2023-02-16 00:02:02 -05:00
|
|
|
assert mock_makessl.called is False
|
|
|
|
|
assert vhs[0] == self.vh_truth[1]
|
2018-02-28 14:31:47 -05:00
|
|
|
|
2019-11-25 12:44:40 -05:00
|
|
|
@mock.patch("certbot_apache._internal.configurator.ApacheConfigurator._vhosts_for_wildcard")
|
|
|
|
|
@mock.patch("certbot_apache._internal.configurator.ApacheConfigurator.make_vhost_ssl")
|
2018-02-28 14:31:47 -05:00
|
|
|
def test_choose_vhosts_wildcard_already_ssl(self, mock_makessl, mock_vh_for_w):
|
|
|
|
|
# pylint: disable=protected-access
|
|
|
|
|
# Already SSL vhost
|
|
|
|
|
mock_vh_for_w.return_value = [self.vh_truth[7]]
|
2019-11-25 12:44:40 -05:00
|
|
|
mock_path = "certbot_apache._internal.display_ops.select_vhost_multiple"
|
2018-02-28 14:31:47 -05:00
|
|
|
with mock.patch(mock_path) as mock_select_vhs:
|
|
|
|
|
mock_select_vhs.return_value = [self.vh_truth[7]]
|
|
|
|
|
vhs = self.config._choose_vhosts_wildcard("whatever",
|
|
|
|
|
create_ssl=True)
|
2023-02-16 00:02:02 -05:00
|
|
|
assert mock_select_vhs.call_args[0][0][0] == self.vh_truth[7]
|
|
|
|
|
assert len(mock_select_vhs.call_args_list) == 1
|
2018-02-28 14:31:47 -05:00
|
|
|
# Ensure that make_vhost_ssl was not called, vhost.ssl == true
|
2023-02-16 00:02:02 -05:00
|
|
|
assert mock_makessl.called is False
|
2018-02-28 14:31:47 -05:00
|
|
|
|
|
|
|
|
# And the actual returned values
|
2023-02-16 00:02:02 -05:00
|
|
|
assert len(vhs) == 1
|
|
|
|
|
assert vhs[0].ssl is True
|
|
|
|
|
assert vhs[0] == self.vh_truth[7]
|
2018-02-28 14:31:47 -05:00
|
|
|
|
Command-line UX overhaul (#8852)
Streamline and reorganize Certbot's CLI output.
This change is a substantial command-line UX overhaul,
based on previous user research. The main goal was to streamline
and clarify output. To see more verbose output, use the -v or -vv flags.
---
* nginx,apache: CLI logging changes
- Add "Successfully deployed ..." message using display_util
- Remove IReporter usage and replace with display_util
- Standardize "... could not find a VirtualHost ..." error
This changes also bumps the version of certbot required by certbot-nginx
and certbot-apache to take use of the new display_util function.
* fix certbot_compatibility_test
since the http plugins now require IDisplay, we need to inject it
* fix dependency version on certbot
* use better asserts
* try fix oldest deps
because certbot 1.10.0 depends on acme>=1.8.0, we need to use
acme==1.8.0 in the -oldest tests
* cli: redesign output of new certificate reporting
Changes the output of run, certonly and certonly --csr. No longer uses
IReporter.
* cli: redesign output of failed authz reporting
* fix problem sorting to be stable between py2 & 3
* add some catch-all error text
* cli: dont use IReporter for EFF donation prompt
* add per-authenticator hints
* pass achalls to auth_hint, write some tests
* exclude static auth hints from coverage
* dont call auth_hint unless derived from .Plugin
* dns fallback hint: dont assume --dns-blah works
--dns-blah won't work for third-party plugins, they need to be specified
using --authenticator dns-blah.
* add code comments about the auth_hint interface
* renew: don't restart the installer for dry-runs
Prevents Certbot from superfluously invoking the installer restart
during dry-run renewals. (This does not affect authenticator restarts).
Additionally removes some CLI output that was reporting the fullchain
path of the renewed certificate.
* update CHANGELOG.md
* cli: redesign output when cert installation failed
- Display a message when certificate installation begins.
- Don't use IReporter, just log errors immediately if restart/rollback
fails.
- Prompt the user with a command to retry the installation process once
they have fixed any underlying problems.
* vary by preconfigured_renewal
and move expiry date to be above the renewal advice
* update code comment
Co-authored-by: ohemorange <ebportnoy@gmail.com>
* update code comment
Co-authored-by: ohemorange <ebportnoy@gmail.com>
* fix lint
* derve cert name from cert_path, if possible
* fix type annotation
* text change in nginx hint
Co-authored-by: ohemorange <ebportnoy@gmail.com>
* print message when restarting server after renewal
* log: print "advice" when exiting with an error
When running in non-quiet mode.
* try fix -oldest lock_test.py
* fix docstring
* s/Restarting/Reloading/ when notifying the user
* fix test name
Co-authored-by: ohemorange <ebportnoy@gmail.com>
* type annotations
* s/using the {} plugin/installer: {}/
* copy: avoid "plugin" where possible
* link to user guide#automated-renewals
when not running with --preconfigured-renewal
* cli: reduce default logging verbosity
* fix lock_test: -vv is needed to see logger.debug
* Change comment in log.py to match the change to default verbosity
* Audit and adjust logging levels in apache module
* Audit and adjust logging levels in nginx module
* Audit, adjust logging levels, and improve logging calls in certbot module
* Fix tests to mock correct methods and classes
* typo in non-preconfigured-renewal message
Co-authored-by: ohemorange <ebportnoy@gmail.com>
* fix test
* revert acme version bump
* catch up to python3 changes
* Revert "revert acme version bump"
This reverts commit fa83d6a51cf8d0e7e17da53c6b751ad12945d0cf.
* Change ocsp check error to warning since it's non-fatal
* Update storage_test in parallel with last change
* get rid of leading newline on "Deploying [...]"
* shrink renewal and installation success messages
* print logfile rather than logdir in exit handler
* Decrease logging level to info for idempotent operation where enhancement is already set
* Display cert not yet due for renewal message when renewing and no other action will be taken, and change cert to certificate
* also write to logger so it goes in the log file
* Don't double write to log file; fix main test
* cli: remove trailing newline on new cert reporting
* ignore type error
* revert accidental changes to dependencies
* Pass tests in any timezone by using utcfromtimestamp
* Add changelog entry
* fix nits
* Improve wording of try again message
* minor wording change to changelog
* hooks: send hook stdout to CLI stdout
includes both --manual and --{pre,post,renew} hooks
* update docstrings and remove TODO
* add a pending deprecation on execute_command
* add test coverage for both
* update deprecation text
Co-authored-by: ohemorange <ebportnoy@gmail.com>
Co-authored-by: Alex Zorin <alex@zorin.id.au>
Co-authored-by: alexzorin <alex@zor.io>
2021-05-24 20:47:39 -04:00
|
|
|
@mock.patch('certbot_apache._internal.configurator.display_util.notify')
|
|
|
|
|
def test_deploy_cert_wildcard(self, unused_mock_notify):
|
2018-02-28 14:31:47 -05:00
|
|
|
# pylint: disable=protected-access
|
|
|
|
|
mock_choose_vhosts = mock.MagicMock()
|
|
|
|
|
mock_choose_vhosts.return_value = [self.vh_truth[7]]
|
|
|
|
|
self.config._choose_vhosts_wildcard = mock_choose_vhosts
|
2019-11-25 12:44:40 -05:00
|
|
|
mock_d = "certbot_apache._internal.configurator.ApacheConfigurator._deploy_cert"
|
2018-02-28 14:31:47 -05:00
|
|
|
with mock.patch(mock_d) as mock_dep:
|
|
|
|
|
self.config.deploy_cert("*.wildcard.example.org", "/tmp/path",
|
|
|
|
|
"/tmp/path", "/tmp/path", "/tmp/path")
|
2023-02-16 00:02:02 -05:00
|
|
|
assert mock_dep.called is True
|
|
|
|
|
assert len(mock_dep.call_args_list) == 1
|
|
|
|
|
assert self.vh_truth[7] == mock_dep.call_args_list[0][0][0]
|
2018-02-28 14:31:47 -05:00
|
|
|
|
2019-11-25 12:44:40 -05:00
|
|
|
@mock.patch("certbot_apache._internal.display_ops.select_vhost_multiple")
|
2018-02-28 14:31:47 -05:00
|
|
|
def test_deploy_cert_wildcard_no_vhosts(self, mock_dialog):
|
|
|
|
|
# pylint: disable=protected-access
|
|
|
|
|
mock_dialog.return_value = []
|
2023-02-16 00:02:02 -05:00
|
|
|
with pytest.raises(errors.PluginError):
|
|
|
|
|
self.config.deploy_cert("*.wild.cat", "/tmp/path", "/tmp/path",
|
2018-02-28 14:31:47 -05:00
|
|
|
"/tmp/path", "/tmp/path")
|
|
|
|
|
|
2019-11-25 12:44:40 -05:00
|
|
|
@mock.patch("certbot_apache._internal.configurator.ApacheConfigurator._choose_vhosts_wildcard")
|
2018-02-28 14:31:47 -05:00
|
|
|
def test_enhance_wildcard_after_install(self, mock_choose):
|
|
|
|
|
# pylint: disable=protected-access
|
2020-03-23 19:49:52 -04:00
|
|
|
self.config.parser.modules["mod_ssl.c"] = None
|
|
|
|
|
self.config.parser.modules["headers_module"] = None
|
2018-04-18 14:08:30 -04:00
|
|
|
self.vh_truth[3].ssl = True
|
2018-02-28 14:31:47 -05:00
|
|
|
self.config._wildcard_vhosts["*.certbot.demo"] = [self.vh_truth[3]]
|
|
|
|
|
self.config.enhance("*.certbot.demo", "ensure-http-header",
|
|
|
|
|
"Upgrade-Insecure-Requests")
|
2023-02-16 00:02:02 -05:00
|
|
|
assert mock_choose.called is False
|
2018-02-28 14:31:47 -05:00
|
|
|
|
2019-11-25 12:44:40 -05:00
|
|
|
@mock.patch("certbot_apache._internal.configurator.ApacheConfigurator._choose_vhosts_wildcard")
|
2018-02-28 14:31:47 -05:00
|
|
|
def test_enhance_wildcard_no_install(self, mock_choose):
|
2018-04-18 14:08:30 -04:00
|
|
|
self.vh_truth[3].ssl = True
|
2018-02-28 14:31:47 -05:00
|
|
|
mock_choose.return_value = [self.vh_truth[3]]
|
2020-03-23 19:49:52 -04:00
|
|
|
self.config.parser.modules["mod_ssl.c"] = None
|
|
|
|
|
self.config.parser.modules["headers_module"] = None
|
2018-02-28 14:31:47 -05:00
|
|
|
self.config.enhance("*.certbot.demo", "ensure-http-header",
|
|
|
|
|
"Upgrade-Insecure-Requests")
|
2023-02-16 00:02:02 -05:00
|
|
|
assert mock_choose.called is True
|
2018-02-28 14:31:47 -05:00
|
|
|
|
2018-06-21 10:27:19 -04:00
|
|
|
def test_add_vhost_id(self):
|
|
|
|
|
for vh in [self.vh_truth[0], self.vh_truth[1], self.vh_truth[2]]:
|
|
|
|
|
vh_id = self.config.add_vhost_id(vh)
|
2023-02-16 00:02:02 -05:00
|
|
|
assert vh == self.config.find_vhost_by_id(vh_id)
|
2018-06-21 10:27:19 -04:00
|
|
|
|
|
|
|
|
def test_find_vhost_by_id_404(self):
|
2023-02-16 00:02:02 -05:00
|
|
|
with pytest.raises(errors.PluginError):
|
|
|
|
|
self.config.find_vhost_by_id("nonexistent")
|
2018-06-21 10:27:19 -04:00
|
|
|
|
|
|
|
|
def test_add_vhost_id_already_exists(self):
|
|
|
|
|
first_id = self.config.add_vhost_id(self.vh_truth[0])
|
|
|
|
|
second_id = self.config.add_vhost_id(self.vh_truth[0])
|
2023-02-16 00:02:02 -05:00
|
|
|
assert first_id == second_id
|
2018-06-21 10:27:19 -04:00
|
|
|
|
2019-03-27 13:10:52 -04:00
|
|
|
def test_realpath_replaces_symlink(self):
|
2019-06-28 11:39:13 -04:00
|
|
|
orig_match = self.config.parser.aug.match
|
2019-03-27 13:10:52 -04:00
|
|
|
mock_vhost = copy.deepcopy(self.vh_truth[0])
|
|
|
|
|
mock_vhost.filep = mock_vhost.filep.replace('sites-enabled', u'sites-available')
|
|
|
|
|
mock_vhost.path = mock_vhost.path.replace('sites-enabled', 'sites-available')
|
|
|
|
|
mock_vhost.enabled = False
|
|
|
|
|
self.config.parser.parse_file(mock_vhost.filep)
|
|
|
|
|
|
|
|
|
|
def mock_match(aug_expr):
|
|
|
|
|
"""Return a mocked match list of VirtualHosts"""
|
|
|
|
|
if "/mocked/path" in aug_expr:
|
|
|
|
|
return [self.vh_truth[1].path, self.vh_truth[0].path, mock_vhost.path]
|
|
|
|
|
return orig_match(aug_expr)
|
|
|
|
|
|
|
|
|
|
self.config.parser.parser_paths = ["/mocked/path"]
|
2019-06-28 11:39:13 -04:00
|
|
|
self.config.parser.aug.match = mock_match
|
2019-03-27 13:10:52 -04:00
|
|
|
vhs = self.config.get_virtual_hosts()
|
2023-02-16 00:02:02 -05:00
|
|
|
assert len(vhs) == 2
|
|
|
|
|
assert vhs[0] == self.vh_truth[1]
|
2019-03-27 13:10:52 -04:00
|
|
|
# mock_vhost should have replaced the vh_truth[0], because its filepath
|
|
|
|
|
# isn't a symlink
|
2023-02-16 00:02:02 -05:00
|
|
|
assert vhs[1] == mock_vhost
|
2019-03-27 13:10:52 -04:00
|
|
|
|
2018-02-28 14:31:47 -05:00
|
|
|
|
2016-06-28 20:56:31 -04:00
|
|
|
class AugeasVhostsTest(util.ApacheTest):
|
2017-10-19 14:23:07 -04:00
|
|
|
"""Test vhosts with illegal names dependent on augeas version."""
|
2016-07-11 16:20:31 -04:00
|
|
|
# pylint: disable=protected-access
|
2016-06-28 20:56:31 -04:00
|
|
|
|
|
|
|
|
def setUp(self): # pylint: disable=arguments-differ
|
2016-06-29 14:55:22 -04:00
|
|
|
td = "debian_apache_2_4/augeas_vhosts"
|
|
|
|
|
cr = "debian_apache_2_4/augeas_vhosts/apache2"
|
|
|
|
|
vr = "debian_apache_2_4/augeas_vhosts/apache2/sites-available"
|
2021-04-08 16:04:51 -04:00
|
|
|
super().setUp(test_dir=td,
|
|
|
|
|
config_root=cr,
|
|
|
|
|
vhost_root=vr)
|
2016-06-28 20:56:31 -04:00
|
|
|
|
|
|
|
|
self.config = util.get_apache_configurator(
|
Distribution specific override functionality based on class inheritance (#5202)
Class inheritance based approach to distro specific overrides.
How it works:
The certbot-apache plugin entrypoint has been changed to entrypoint.ENTRYPOINT which is a variable containing appropriate override class for system, if available.
Override classes register themselves using decorator override.register() which takes a list of distribution fingerprints (ID & LIKE variables in /etc/os-release, or platform.linux_distribution() as a fallback). These end up as keys in dict override.OVERRIDE_CLASSES and values for the keys are references to the class that called the decorator, hence allowing self-registration of override classes when they are imported. The only file importing these override classes is entrypoint.py, so adding new override classes would need only one import in addition to the actual override class file.
Generic changes:
Parser initialization has been moved to separate class method, allowing easy override where needed.
Cleaned up configurator.py a bit, and moved some helper functions to newly created apache_util.py
Split Debian specific code from configurator.py to debian_override.py
Changed define_cmd to apache_cmd because the parameters are for every distribution supporting this behavior, and we're able to use the value to build the additional configuration dump commands.
Moved add_parser_mod() from configurator to parser add_mod()
Added two new configuration dump parsing methods to update_runtime_variables() in parser: update_includes() and update_modules().
Changed init_modules() in parser to accommodate the changes above. (ie. don't throw existing self.modules out).
Moved OS based constants to their respective override classes.
Refactored configurator class discovery in tests to help easier test case creation using distribution based override configurator class.
tests.util.get_apache_configurator() now takes keyword argument os_info which is string of the desired mock OS fingerprint response that's used for picking the right override class.
This PR includes two major generic additions that should vastly improve our parsing accuracy and quality:
Includes are parsed from config dump from httpd binary. This is mandatory for some distributions (Like OpenSUSE) to get visibility over the whole configuration tree because of Include statements passed on in command line, and not via root httpd.conf file.
Modules are parsed from config dump from httpd binary. This lets us jump into correct IfModule directives if for some reason we have missed the module availability (because of one being included on command line or such).
Distribution specific changes
Because of the generic changes, there are two distributions (or distribution families) that do not provide such functionality, so it had to be overridden in their respective override files. These distributions are:
CentOS, because it deliberately limits httpd binary stdout using SELinux as a feature. We are doing opportunistic config dumps here however, in case SELinux enforcing is off.
Gentoo, because it does not provide a way to invoke httpd with command line parsed from its specific configuration file. Gentoo relies heavily on Define statements that are passed over from APACHE2_OPTS variable /etc/conf.d/apache2 file and most of the configuration in root Apache configuration are dependent on these values.
Debian
Moved the Debian specific parts from configurator.py to Debian specific override.
CentOS
Parsing of /etc/sysconfig/httpd file for additional Define statements. This could hold other parameters too, but parsing everything off it would require a full Apache lexer. For CLI parameters, I think Defines are the most common ones. This is done in addition of opportunistic parsing of httpd binary config dump.
Added CentOS default Apache configuration tree for realistic test cases.
Gentoo
Parsing Defines from /etc/conf.d/apache2 variable APACHE2_OPTS, which holds additional Define statements to enable certain functionalities, enabling parts of the configuration in the Apache2 DOM. This is done instead of trying to parse httpd binary configuration dumps.
Added default Apache configuration from Gentoo to testdata, including /etc/conf.d/apache2 file for realistic test cases.
* Distribution specific override functionality based on class inheritance
* Need to patch get_systemd_os_like to as travis has proper os-release
* Added pydoc
* Move parser initialization to a method and fix Python 3 __new__ errors
* Parser changes to parse HTTPD config
* Try to get modules and includes from httpd process for better visibility over the configuration
* Had to disable duplicate-code because of test setup (PyCQA/pylint/issues/214)
* CentOS tests and linter fixes
* Gentoo override, tests and linter fixes
* Mock the process call in all the tests that require it
* Fix CentOS test mock
* Restore reseting modules list functionality for cleanup
* Move OS fingerprinting and constant mocks to parent class
* Fixes requested in review
* New entrypoint structure and started moving OS constants to override classes
* OS constants move continued, test and linter fixes
* Removed dead code
* Apache compatibility test changest to reflect OS constant restructure
* Test fix
* Requested changes
* Moved Debian specific tests to own test file
* Removed decorator based override class registration in favor of entrypoint dict
* Fix for update_includes for some versions of Augeas
* Take fedora fix into account in tests
* Review fixes
2017-12-04 14:49:18 -05:00
|
|
|
self.config_path, self.vhost_path, self.config_dir,
|
|
|
|
|
self.work_dir)
|
2016-06-28 20:56:31 -04:00
|
|
|
|
|
|
|
|
def test_choosevhost_with_illegal_name(self):
|
2019-06-28 11:39:13 -04:00
|
|
|
self.config.parser.aug = mock.MagicMock()
|
|
|
|
|
self.config.parser.aug.match.side_effect = RuntimeError
|
2019-01-24 14:37:36 -05:00
|
|
|
path = "debian_apache_2_4/augeas_vhosts/apache2/sites-available/old-and-default.conf"
|
2016-06-29 14:55:22 -04:00
|
|
|
chosen_vhost = self.config._create_vhost(path)
|
2023-02-16 00:02:02 -05:00
|
|
|
assert None == chosen_vhost
|
2015-02-09 03:12:43 -05:00
|
|
|
|
2016-06-28 21:08:38 -04:00
|
|
|
def test_choosevhost_works(self):
|
2019-01-24 14:37:36 -05:00
|
|
|
path = "debian_apache_2_4/augeas_vhosts/apache2/sites-available/old-and-default.conf"
|
2016-06-28 21:08:38 -04:00
|
|
|
chosen_vhost = self.config._create_vhost(path)
|
2023-02-16 00:02:02 -05:00
|
|
|
assert chosen_vhost is None or chosen_vhost.path == path
|
2016-06-28 21:08:38 -04:00
|
|
|
|
2019-11-25 12:44:40 -05:00
|
|
|
@mock.patch("certbot_apache._internal.configurator.ApacheConfigurator._create_vhost")
|
2016-06-29 14:06:18 -04:00
|
|
|
def test_get_vhost_continue(self, mock_vhost):
|
|
|
|
|
mock_vhost.return_value = None
|
|
|
|
|
vhs = self.config.get_virtual_hosts()
|
2023-02-16 00:02:02 -05:00
|
|
|
assert [] == vhs
|
2015-02-09 03:12:43 -05:00
|
|
|
|
2016-12-20 18:53:52 -05:00
|
|
|
def test_choose_vhost_with_matching_wildcard(self):
|
|
|
|
|
names = (
|
|
|
|
|
"an.example.net", "another.example.net", "an.other.example.net")
|
|
|
|
|
for name in names:
|
2022-01-03 16:05:21 -05:00
|
|
|
with self.subTest(name=name):
|
2023-02-16 00:02:02 -05:00
|
|
|
assert name not in self.config.choose_vhost(name).aliases
|
2016-12-20 18:53:52 -05:00
|
|
|
|
2019-11-25 12:44:40 -05:00
|
|
|
@mock.patch("certbot_apache._internal.obj.VirtualHost.conflicts")
|
2017-09-25 15:03:09 -04:00
|
|
|
def test_choose_vhost_without_matching_wildcard(self, mock_conflicts):
|
|
|
|
|
mock_conflicts.return_value = False
|
2019-11-25 12:44:40 -05:00
|
|
|
mock_path = "certbot_apache._internal.display_ops.select_vhost"
|
2016-12-20 18:53:52 -05:00
|
|
|
with mock.patch(mock_path, lambda _, vhosts: vhosts[0]):
|
|
|
|
|
for name in ("a.example.net", "other.example.net"):
|
2023-02-16 00:02:02 -05:00
|
|
|
assert name in self.config.choose_vhost(name).aliases
|
2016-12-20 18:53:52 -05:00
|
|
|
|
2019-11-25 12:44:40 -05:00
|
|
|
@mock.patch("certbot_apache._internal.obj.VirtualHost.conflicts")
|
2017-09-25 15:03:09 -04:00
|
|
|
def test_choose_vhost_wildcard_not_found(self, mock_conflicts):
|
|
|
|
|
mock_conflicts.return_value = False
|
2019-11-25 12:44:40 -05:00
|
|
|
mock_path = "certbot_apache._internal.display_ops.select_vhost"
|
2016-12-20 18:53:52 -05:00
|
|
|
names = (
|
|
|
|
|
"abc.example.net", "not.there.tld", "aa.wildcard.tld"
|
|
|
|
|
)
|
|
|
|
|
with mock.patch(mock_path) as mock_select:
|
|
|
|
|
mock_select.return_value = self.config.vhosts[0]
|
|
|
|
|
for name in names:
|
|
|
|
|
orig_cc = mock_select.call_count
|
|
|
|
|
self.config.choose_vhost(name)
|
2023-02-16 00:02:02 -05:00
|
|
|
assert mock_select.call_count - orig_cc == 1
|
2016-12-20 18:53:52 -05:00
|
|
|
|
|
|
|
|
def test_choose_vhost_wildcard_found(self):
|
2019-11-25 12:44:40 -05:00
|
|
|
mock_path = "certbot_apache._internal.display_ops.select_vhost"
|
2016-12-20 18:53:52 -05:00
|
|
|
names = (
|
|
|
|
|
"ab.example.net", "a.wildcard.tld", "yetanother.example.net"
|
|
|
|
|
)
|
|
|
|
|
with mock.patch(mock_path) as mock_select:
|
|
|
|
|
mock_select.return_value = self.config.vhosts[0]
|
|
|
|
|
for name in names:
|
|
|
|
|
self.config.choose_vhost(name)
|
2023-02-16 00:02:02 -05:00
|
|
|
assert mock_select.call_count == 0
|
2016-12-20 18:53:52 -05:00
|
|
|
|
2016-09-28 14:34:27 -04:00
|
|
|
def test_augeas_span_error(self):
|
|
|
|
|
broken_vhost = self.config.vhosts[0]
|
|
|
|
|
broken_vhost.path = broken_vhost.path + "/nonexistent"
|
2023-02-16 00:02:02 -05:00
|
|
|
with pytest.raises(errors.PluginError):
|
|
|
|
|
self.config.make_vhost_ssl(broken_vhost)
|
2016-09-28 14:34:27 -04:00
|
|
|
|
2022-01-03 16:05:21 -05:00
|
|
|
|
2016-07-26 18:57:11 -04:00
|
|
|
class MultiVhostsTest(util.ApacheTest):
|
2018-08-02 11:17:38 -04:00
|
|
|
"""Test configuration with multiple virtualhosts in a single file."""
|
2016-07-26 18:57:11 -04:00
|
|
|
# pylint: disable=protected-access
|
|
|
|
|
|
|
|
|
|
def setUp(self): # pylint: disable=arguments-differ
|
|
|
|
|
td = "debian_apache_2_4/multi_vhosts"
|
|
|
|
|
cr = "debian_apache_2_4/multi_vhosts/apache2"
|
|
|
|
|
vr = "debian_apache_2_4/multi_vhosts/apache2/sites-available"
|
2022-01-03 16:05:21 -05:00
|
|
|
super().setUp(test_dir=td, config_root=cr, vhost_root=vr)
|
2016-07-26 18:57:11 -04:00
|
|
|
|
|
|
|
|
self.config = util.get_apache_configurator(
|
Distribution specific override functionality based on class inheritance (#5202)
Class inheritance based approach to distro specific overrides.
How it works:
The certbot-apache plugin entrypoint has been changed to entrypoint.ENTRYPOINT which is a variable containing appropriate override class for system, if available.
Override classes register themselves using decorator override.register() which takes a list of distribution fingerprints (ID & LIKE variables in /etc/os-release, or platform.linux_distribution() as a fallback). These end up as keys in dict override.OVERRIDE_CLASSES and values for the keys are references to the class that called the decorator, hence allowing self-registration of override classes when they are imported. The only file importing these override classes is entrypoint.py, so adding new override classes would need only one import in addition to the actual override class file.
Generic changes:
Parser initialization has been moved to separate class method, allowing easy override where needed.
Cleaned up configurator.py a bit, and moved some helper functions to newly created apache_util.py
Split Debian specific code from configurator.py to debian_override.py
Changed define_cmd to apache_cmd because the parameters are for every distribution supporting this behavior, and we're able to use the value to build the additional configuration dump commands.
Moved add_parser_mod() from configurator to parser add_mod()
Added two new configuration dump parsing methods to update_runtime_variables() in parser: update_includes() and update_modules().
Changed init_modules() in parser to accommodate the changes above. (ie. don't throw existing self.modules out).
Moved OS based constants to their respective override classes.
Refactored configurator class discovery in tests to help easier test case creation using distribution based override configurator class.
tests.util.get_apache_configurator() now takes keyword argument os_info which is string of the desired mock OS fingerprint response that's used for picking the right override class.
This PR includes two major generic additions that should vastly improve our parsing accuracy and quality:
Includes are parsed from config dump from httpd binary. This is mandatory for some distributions (Like OpenSUSE) to get visibility over the whole configuration tree because of Include statements passed on in command line, and not via root httpd.conf file.
Modules are parsed from config dump from httpd binary. This lets us jump into correct IfModule directives if for some reason we have missed the module availability (because of one being included on command line or such).
Distribution specific changes
Because of the generic changes, there are two distributions (or distribution families) that do not provide such functionality, so it had to be overridden in their respective override files. These distributions are:
CentOS, because it deliberately limits httpd binary stdout using SELinux as a feature. We are doing opportunistic config dumps here however, in case SELinux enforcing is off.
Gentoo, because it does not provide a way to invoke httpd with command line parsed from its specific configuration file. Gentoo relies heavily on Define statements that are passed over from APACHE2_OPTS variable /etc/conf.d/apache2 file and most of the configuration in root Apache configuration are dependent on these values.
Debian
Moved the Debian specific parts from configurator.py to Debian specific override.
CentOS
Parsing of /etc/sysconfig/httpd file for additional Define statements. This could hold other parameters too, but parsing everything off it would require a full Apache lexer. For CLI parameters, I think Defines are the most common ones. This is done in addition of opportunistic parsing of httpd binary config dump.
Added CentOS default Apache configuration tree for realistic test cases.
Gentoo
Parsing Defines from /etc/conf.d/apache2 variable APACHE2_OPTS, which holds additional Define statements to enable certain functionalities, enabling parts of the configuration in the Apache2 DOM. This is done instead of trying to parse httpd binary configuration dumps.
Added default Apache configuration from Gentoo to testdata, including /etc/conf.d/apache2 file for realistic test cases.
* Distribution specific override functionality based on class inheritance
* Need to patch get_systemd_os_like to as travis has proper os-release
* Added pydoc
* Move parser initialization to a method and fix Python 3 __new__ errors
* Parser changes to parse HTTPD config
* Try to get modules and includes from httpd process for better visibility over the configuration
* Had to disable duplicate-code because of test setup (PyCQA/pylint/issues/214)
* CentOS tests and linter fixes
* Gentoo override, tests and linter fixes
* Mock the process call in all the tests that require it
* Fix CentOS test mock
* Restore reseting modules list functionality for cleanup
* Move OS fingerprinting and constant mocks to parent class
* Fixes requested in review
* New entrypoint structure and started moving OS constants to override classes
* OS constants move continued, test and linter fixes
* Removed dead code
* Apache compatibility test changest to reflect OS constant restructure
* Test fix
* Requested changes
* Moved Debian specific tests to own test file
* Removed decorator based override class registration in favor of entrypoint dict
* Fix for update_includes for some versions of Augeas
* Take fedora fix into account in tests
* Review fixes
2017-12-04 14:49:18 -05:00
|
|
|
self.config_path, self.vhost_path,
|
|
|
|
|
self.config_dir, self.work_dir, conf_vhost_path=self.vhost_path)
|
2016-07-26 18:57:11 -04:00
|
|
|
self.vh_truth = util.get_vh_truth(
|
|
|
|
|
self.temp_dir, "debian_apache_2_4/multi_vhosts")
|
|
|
|
|
|
|
|
|
|
def test_make_vhost_ssl(self):
|
|
|
|
|
ssl_vhost = self.config.make_vhost_ssl(self.vh_truth[1])
|
|
|
|
|
|
2023-02-16 00:02:02 -05:00
|
|
|
assert ssl_vhost.filep == \
|
2016-07-26 18:57:11 -04:00
|
|
|
os.path.join(self.config_path, "sites-available",
|
2023-02-16 00:02:02 -05:00
|
|
|
"default-le-ssl.conf")
|
2016-07-26 18:57:11 -04:00
|
|
|
|
2023-02-16 00:02:02 -05:00
|
|
|
assert ssl_vhost.path == \
|
|
|
|
|
"/files" + ssl_vhost.filep + "/IfModule/VirtualHost"
|
|
|
|
|
assert len(ssl_vhost.addrs) == 1
|
|
|
|
|
assert {obj.Addr.fromstring("*:443")} == ssl_vhost.addrs
|
|
|
|
|
assert ssl_vhost.name == "banana.vomit.com"
|
|
|
|
|
assert ssl_vhost.ssl is True
|
|
|
|
|
assert ssl_vhost.enabled is False
|
2016-07-26 18:57:11 -04:00
|
|
|
|
2019-11-25 12:44:40 -05:00
|
|
|
mock_path = "certbot_apache._internal.configurator.ApacheConfigurator._get_new_vh_path"
|
2016-09-28 14:34:27 -04:00
|
|
|
with mock.patch(mock_path) as mock_getpath:
|
|
|
|
|
mock_getpath.return_value = None
|
2023-02-16 00:02:02 -05:00
|
|
|
with pytest.raises(errors.PluginError):
|
|
|
|
|
self.config.make_vhost_ssl(self.vh_truth[1])
|
2016-09-28 14:34:27 -04:00
|
|
|
|
|
|
|
|
def test_get_new_path(self):
|
|
|
|
|
with_index_1 = ["/path[1]/section[1]"]
|
|
|
|
|
without_index = ["/path/section"]
|
|
|
|
|
with_index_2 = ["/path[2]/section[2]"]
|
2023-02-16 00:02:02 -05:00
|
|
|
assert self.config._get_new_vh_path(without_index,
|
|
|
|
|
with_index_1) == \
|
|
|
|
|
None
|
|
|
|
|
assert self.config._get_new_vh_path(without_index,
|
|
|
|
|
with_index_2) == \
|
|
|
|
|
with_index_2[0]
|
2016-09-28 14:34:27 -04:00
|
|
|
|
|
|
|
|
both = with_index_1 + with_index_2
|
2023-02-16 00:02:02 -05:00
|
|
|
assert self.config._get_new_vh_path(without_index, both) == \
|
|
|
|
|
with_index_2[0]
|
2016-09-28 14:34:27 -04:00
|
|
|
|
Command-line UX overhaul (#8852)
Streamline and reorganize Certbot's CLI output.
This change is a substantial command-line UX overhaul,
based on previous user research. The main goal was to streamline
and clarify output. To see more verbose output, use the -v or -vv flags.
---
* nginx,apache: CLI logging changes
- Add "Successfully deployed ..." message using display_util
- Remove IReporter usage and replace with display_util
- Standardize "... could not find a VirtualHost ..." error
This changes also bumps the version of certbot required by certbot-nginx
and certbot-apache to take use of the new display_util function.
* fix certbot_compatibility_test
since the http plugins now require IDisplay, we need to inject it
* fix dependency version on certbot
* use better asserts
* try fix oldest deps
because certbot 1.10.0 depends on acme>=1.8.0, we need to use
acme==1.8.0 in the -oldest tests
* cli: redesign output of new certificate reporting
Changes the output of run, certonly and certonly --csr. No longer uses
IReporter.
* cli: redesign output of failed authz reporting
* fix problem sorting to be stable between py2 & 3
* add some catch-all error text
* cli: dont use IReporter for EFF donation prompt
* add per-authenticator hints
* pass achalls to auth_hint, write some tests
* exclude static auth hints from coverage
* dont call auth_hint unless derived from .Plugin
* dns fallback hint: dont assume --dns-blah works
--dns-blah won't work for third-party plugins, they need to be specified
using --authenticator dns-blah.
* add code comments about the auth_hint interface
* renew: don't restart the installer for dry-runs
Prevents Certbot from superfluously invoking the installer restart
during dry-run renewals. (This does not affect authenticator restarts).
Additionally removes some CLI output that was reporting the fullchain
path of the renewed certificate.
* update CHANGELOG.md
* cli: redesign output when cert installation failed
- Display a message when certificate installation begins.
- Don't use IReporter, just log errors immediately if restart/rollback
fails.
- Prompt the user with a command to retry the installation process once
they have fixed any underlying problems.
* vary by preconfigured_renewal
and move expiry date to be above the renewal advice
* update code comment
Co-authored-by: ohemorange <ebportnoy@gmail.com>
* update code comment
Co-authored-by: ohemorange <ebportnoy@gmail.com>
* fix lint
* derve cert name from cert_path, if possible
* fix type annotation
* text change in nginx hint
Co-authored-by: ohemorange <ebportnoy@gmail.com>
* print message when restarting server after renewal
* log: print "advice" when exiting with an error
When running in non-quiet mode.
* try fix -oldest lock_test.py
* fix docstring
* s/Restarting/Reloading/ when notifying the user
* fix test name
Co-authored-by: ohemorange <ebportnoy@gmail.com>
* type annotations
* s/using the {} plugin/installer: {}/
* copy: avoid "plugin" where possible
* link to user guide#automated-renewals
when not running with --preconfigured-renewal
* cli: reduce default logging verbosity
* fix lock_test: -vv is needed to see logger.debug
* Change comment in log.py to match the change to default verbosity
* Audit and adjust logging levels in apache module
* Audit and adjust logging levels in nginx module
* Audit, adjust logging levels, and improve logging calls in certbot module
* Fix tests to mock correct methods and classes
* typo in non-preconfigured-renewal message
Co-authored-by: ohemorange <ebportnoy@gmail.com>
* fix test
* revert acme version bump
* catch up to python3 changes
* Revert "revert acme version bump"
This reverts commit fa83d6a51cf8d0e7e17da53c6b751ad12945d0cf.
* Change ocsp check error to warning since it's non-fatal
* Update storage_test in parallel with last change
* get rid of leading newline on "Deploying [...]"
* shrink renewal and installation success messages
* print logfile rather than logdir in exit handler
* Decrease logging level to info for idempotent operation where enhancement is already set
* Display cert not yet due for renewal message when renewing and no other action will be taken, and change cert to certificate
* also write to logger so it goes in the log file
* Don't double write to log file; fix main test
* cli: remove trailing newline on new cert reporting
* ignore type error
* revert accidental changes to dependencies
* Pass tests in any timezone by using utcfromtimestamp
* Add changelog entry
* fix nits
* Improve wording of try again message
* minor wording change to changelog
* hooks: send hook stdout to CLI stdout
includes both --manual and --{pre,post,renew} hooks
* update docstrings and remove TODO
* add a pending deprecation on execute_command
* add test coverage for both
* update deprecation text
Co-authored-by: ohemorange <ebportnoy@gmail.com>
Co-authored-by: Alex Zorin <alex@zorin.id.au>
Co-authored-by: alexzorin <alex@zor.io>
2021-05-24 20:47:39 -04:00
|
|
|
@mock.patch("certbot_apache._internal.configurator.display_util.notify")
|
|
|
|
|
def test_make_vhost_ssl_with_existing_rewrite_rule(self, mock_notify):
|
2020-03-23 19:49:52 -04:00
|
|
|
self.config.parser.modules["rewrite_module"] = None
|
2016-09-28 14:34:27 -04:00
|
|
|
|
|
|
|
|
ssl_vhost = self.config.make_vhost_ssl(self.vh_truth[4])
|
2016-07-26 18:57:11 -04:00
|
|
|
|
2023-02-16 00:02:02 -05:00
|
|
|
assert self.config.parser.find_dir("RewriteEngine", "on", ssl_vhost.path, False)
|
2016-09-28 14:34:27 -04:00
|
|
|
|
2018-11-01 19:39:54 -04:00
|
|
|
with open(ssl_vhost.filep) as the_file:
|
|
|
|
|
conf_text = the_file.read()
|
2016-09-28 14:34:27 -04:00
|
|
|
commented_rewrite_rule = ("# RewriteRule \"^/secrets/(.+)\" "
|
|
|
|
|
"\"https://new.example.com/docs/$1\" [R,L]")
|
|
|
|
|
uncommented_rewrite_rule = ("RewriteRule \"^/docs/(.+)\" "
|
|
|
|
|
"\"http://new.example.com/docs/$1\" [R,L]")
|
2023-02-16 00:02:02 -05:00
|
|
|
assert commented_rewrite_rule in conf_text
|
|
|
|
|
assert uncommented_rewrite_rule in conf_text
|
|
|
|
|
assert mock_notify.call_count == 1
|
|
|
|
|
assert "Some rewrite rules" in mock_notify.call_args[0][0]
|
2016-09-28 14:34:27 -04:00
|
|
|
|
Command-line UX overhaul (#8852)
Streamline and reorganize Certbot's CLI output.
This change is a substantial command-line UX overhaul,
based on previous user research. The main goal was to streamline
and clarify output. To see more verbose output, use the -v or -vv flags.
---
* nginx,apache: CLI logging changes
- Add "Successfully deployed ..." message using display_util
- Remove IReporter usage and replace with display_util
- Standardize "... could not find a VirtualHost ..." error
This changes also bumps the version of certbot required by certbot-nginx
and certbot-apache to take use of the new display_util function.
* fix certbot_compatibility_test
since the http plugins now require IDisplay, we need to inject it
* fix dependency version on certbot
* use better asserts
* try fix oldest deps
because certbot 1.10.0 depends on acme>=1.8.0, we need to use
acme==1.8.0 in the -oldest tests
* cli: redesign output of new certificate reporting
Changes the output of run, certonly and certonly --csr. No longer uses
IReporter.
* cli: redesign output of failed authz reporting
* fix problem sorting to be stable between py2 & 3
* add some catch-all error text
* cli: dont use IReporter for EFF donation prompt
* add per-authenticator hints
* pass achalls to auth_hint, write some tests
* exclude static auth hints from coverage
* dont call auth_hint unless derived from .Plugin
* dns fallback hint: dont assume --dns-blah works
--dns-blah won't work for third-party plugins, they need to be specified
using --authenticator dns-blah.
* add code comments about the auth_hint interface
* renew: don't restart the installer for dry-runs
Prevents Certbot from superfluously invoking the installer restart
during dry-run renewals. (This does not affect authenticator restarts).
Additionally removes some CLI output that was reporting the fullchain
path of the renewed certificate.
* update CHANGELOG.md
* cli: redesign output when cert installation failed
- Display a message when certificate installation begins.
- Don't use IReporter, just log errors immediately if restart/rollback
fails.
- Prompt the user with a command to retry the installation process once
they have fixed any underlying problems.
* vary by preconfigured_renewal
and move expiry date to be above the renewal advice
* update code comment
Co-authored-by: ohemorange <ebportnoy@gmail.com>
* update code comment
Co-authored-by: ohemorange <ebportnoy@gmail.com>
* fix lint
* derve cert name from cert_path, if possible
* fix type annotation
* text change in nginx hint
Co-authored-by: ohemorange <ebportnoy@gmail.com>
* print message when restarting server after renewal
* log: print "advice" when exiting with an error
When running in non-quiet mode.
* try fix -oldest lock_test.py
* fix docstring
* s/Restarting/Reloading/ when notifying the user
* fix test name
Co-authored-by: ohemorange <ebportnoy@gmail.com>
* type annotations
* s/using the {} plugin/installer: {}/
* copy: avoid "plugin" where possible
* link to user guide#automated-renewals
when not running with --preconfigured-renewal
* cli: reduce default logging verbosity
* fix lock_test: -vv is needed to see logger.debug
* Change comment in log.py to match the change to default verbosity
* Audit and adjust logging levels in apache module
* Audit and adjust logging levels in nginx module
* Audit, adjust logging levels, and improve logging calls in certbot module
* Fix tests to mock correct methods and classes
* typo in non-preconfigured-renewal message
Co-authored-by: ohemorange <ebportnoy@gmail.com>
* fix test
* revert acme version bump
* catch up to python3 changes
* Revert "revert acme version bump"
This reverts commit fa83d6a51cf8d0e7e17da53c6b751ad12945d0cf.
* Change ocsp check error to warning since it's non-fatal
* Update storage_test in parallel with last change
* get rid of leading newline on "Deploying [...]"
* shrink renewal and installation success messages
* print logfile rather than logdir in exit handler
* Decrease logging level to info for idempotent operation where enhancement is already set
* Display cert not yet due for renewal message when renewing and no other action will be taken, and change cert to certificate
* also write to logger so it goes in the log file
* Don't double write to log file; fix main test
* cli: remove trailing newline on new cert reporting
* ignore type error
* revert accidental changes to dependencies
* Pass tests in any timezone by using utcfromtimestamp
* Add changelog entry
* fix nits
* Improve wording of try again message
* minor wording change to changelog
* hooks: send hook stdout to CLI stdout
includes both --manual and --{pre,post,renew} hooks
* update docstrings and remove TODO
* add a pending deprecation on execute_command
* add test coverage for both
* update deprecation text
Co-authored-by: ohemorange <ebportnoy@gmail.com>
Co-authored-by: Alex Zorin <alex@zorin.id.au>
Co-authored-by: alexzorin <alex@zor.io>
2021-05-24 20:47:39 -04:00
|
|
|
@mock.patch("certbot_apache._internal.configurator.display_util.notify")
|
|
|
|
|
def test_make_vhost_ssl_with_existing_rewrite_conds(self, mock_notify):
|
2020-03-23 19:49:52 -04:00
|
|
|
self.config.parser.modules["rewrite_module"] = None
|
2016-09-28 14:34:27 -04:00
|
|
|
|
|
|
|
|
ssl_vhost = self.config.make_vhost_ssl(self.vh_truth[3])
|
|
|
|
|
|
2018-11-01 19:39:54 -04:00
|
|
|
with open(ssl_vhost.filep) as the_file:
|
|
|
|
|
conf_lines = the_file.readlines()
|
2016-09-28 14:34:27 -04:00
|
|
|
conf_line_set = [l.strip() for l in conf_lines]
|
|
|
|
|
not_commented_cond1 = ("RewriteCond "
|
|
|
|
|
"%{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f")
|
|
|
|
|
not_commented_rewrite_rule = ("RewriteRule "
|
|
|
|
|
"^(.*)$ b://u%{REQUEST_URI} [P,NE,L]")
|
|
|
|
|
|
|
|
|
|
commented_cond1 = "# RewriteCond %{HTTPS} !=on"
|
|
|
|
|
commented_cond2 = "# RewriteCond %{HTTPS} !^$"
|
|
|
|
|
commented_rewrite_rule = ("# RewriteRule ^ "
|
|
|
|
|
"https://%{SERVER_NAME}%{REQUEST_URI} "
|
|
|
|
|
"[L,NE,R=permanent]")
|
|
|
|
|
|
2023-02-16 00:02:02 -05:00
|
|
|
assert not_commented_cond1 in conf_line_set
|
|
|
|
|
assert not_commented_rewrite_rule in conf_line_set
|
2016-09-28 14:34:27 -04:00
|
|
|
|
2023-02-16 00:02:02 -05:00
|
|
|
assert commented_cond1 in conf_line_set
|
|
|
|
|
assert commented_cond2 in conf_line_set
|
|
|
|
|
assert commented_rewrite_rule in conf_line_set
|
|
|
|
|
assert mock_notify.call_count == 1
|
|
|
|
|
assert "Some rewrite rules" in mock_notify.call_args[0][0]
|
2016-07-26 18:57:11 -04:00
|
|
|
|
2016-12-20 18:53:52 -05:00
|
|
|
|
2017-05-23 19:25:39 -04:00
|
|
|
class InstallSslOptionsConfTest(util.ApacheTest):
|
|
|
|
|
"""Test that the options-ssl-nginx.conf file is installed and updated properly."""
|
|
|
|
|
|
|
|
|
|
def setUp(self): # pylint: disable=arguments-differ
|
2021-04-08 16:04:51 -04:00
|
|
|
super().setUp()
|
2017-05-23 19:25:39 -04:00
|
|
|
|
|
|
|
|
self.config = util.get_apache_configurator(
|
|
|
|
|
self.config_path, self.vhost_path, self.config_dir, self.work_dir)
|
|
|
|
|
|
|
|
|
|
def _call(self):
|
Distribution specific override functionality based on class inheritance (#5202)
Class inheritance based approach to distro specific overrides.
How it works:
The certbot-apache plugin entrypoint has been changed to entrypoint.ENTRYPOINT which is a variable containing appropriate override class for system, if available.
Override classes register themselves using decorator override.register() which takes a list of distribution fingerprints (ID & LIKE variables in /etc/os-release, or platform.linux_distribution() as a fallback). These end up as keys in dict override.OVERRIDE_CLASSES and values for the keys are references to the class that called the decorator, hence allowing self-registration of override classes when they are imported. The only file importing these override classes is entrypoint.py, so adding new override classes would need only one import in addition to the actual override class file.
Generic changes:
Parser initialization has been moved to separate class method, allowing easy override where needed.
Cleaned up configurator.py a bit, and moved some helper functions to newly created apache_util.py
Split Debian specific code from configurator.py to debian_override.py
Changed define_cmd to apache_cmd because the parameters are for every distribution supporting this behavior, and we're able to use the value to build the additional configuration dump commands.
Moved add_parser_mod() from configurator to parser add_mod()
Added two new configuration dump parsing methods to update_runtime_variables() in parser: update_includes() and update_modules().
Changed init_modules() in parser to accommodate the changes above. (ie. don't throw existing self.modules out).
Moved OS based constants to their respective override classes.
Refactored configurator class discovery in tests to help easier test case creation using distribution based override configurator class.
tests.util.get_apache_configurator() now takes keyword argument os_info which is string of the desired mock OS fingerprint response that's used for picking the right override class.
This PR includes two major generic additions that should vastly improve our parsing accuracy and quality:
Includes are parsed from config dump from httpd binary. This is mandatory for some distributions (Like OpenSUSE) to get visibility over the whole configuration tree because of Include statements passed on in command line, and not via root httpd.conf file.
Modules are parsed from config dump from httpd binary. This lets us jump into correct IfModule directives if for some reason we have missed the module availability (because of one being included on command line or such).
Distribution specific changes
Because of the generic changes, there are two distributions (or distribution families) that do not provide such functionality, so it had to be overridden in their respective override files. These distributions are:
CentOS, because it deliberately limits httpd binary stdout using SELinux as a feature. We are doing opportunistic config dumps here however, in case SELinux enforcing is off.
Gentoo, because it does not provide a way to invoke httpd with command line parsed from its specific configuration file. Gentoo relies heavily on Define statements that are passed over from APACHE2_OPTS variable /etc/conf.d/apache2 file and most of the configuration in root Apache configuration are dependent on these values.
Debian
Moved the Debian specific parts from configurator.py to Debian specific override.
CentOS
Parsing of /etc/sysconfig/httpd file for additional Define statements. This could hold other parameters too, but parsing everything off it would require a full Apache lexer. For CLI parameters, I think Defines are the most common ones. This is done in addition of opportunistic parsing of httpd binary config dump.
Added CentOS default Apache configuration tree for realistic test cases.
Gentoo
Parsing Defines from /etc/conf.d/apache2 variable APACHE2_OPTS, which holds additional Define statements to enable certain functionalities, enabling parts of the configuration in the Apache2 DOM. This is done instead of trying to parse httpd binary configuration dumps.
Added default Apache configuration from Gentoo to testdata, including /etc/conf.d/apache2 file for realistic test cases.
* Distribution specific override functionality based on class inheritance
* Need to patch get_systemd_os_like to as travis has proper os-release
* Added pydoc
* Move parser initialization to a method and fix Python 3 __new__ errors
* Parser changes to parse HTTPD config
* Try to get modules and includes from httpd process for better visibility over the configuration
* Had to disable duplicate-code because of test setup (PyCQA/pylint/issues/214)
* CentOS tests and linter fixes
* Gentoo override, tests and linter fixes
* Mock the process call in all the tests that require it
* Fix CentOS test mock
* Restore reseting modules list functionality for cleanup
* Move OS fingerprinting and constant mocks to parent class
* Fixes requested in review
* New entrypoint structure and started moving OS constants to override classes
* OS constants move continued, test and linter fixes
* Removed dead code
* Apache compatibility test changest to reflect OS constant restructure
* Test fix
* Requested changes
* Moved Debian specific tests to own test file
* Removed decorator based override class registration in favor of entrypoint dict
* Fix for update_includes for some versions of Augeas
* Take fedora fix into account in tests
* Review fixes
2017-12-04 14:49:18 -05:00
|
|
|
self.config.install_ssl_options_conf(self.config.mod_ssl_conf,
|
|
|
|
|
self.config.updated_mod_ssl_conf_digest)
|
2017-05-23 19:25:39 -04:00
|
|
|
|
|
|
|
|
def _current_ssl_options_hash(self):
|
2020-03-23 19:49:52 -04:00
|
|
|
return crypto_util.sha256sum(self.config.pick_apache_config())
|
2017-05-23 19:25:39 -04:00
|
|
|
|
|
|
|
|
def _assert_current_file(self):
|
2023-02-16 00:02:02 -05:00
|
|
|
assert os.path.isfile(self.config.mod_ssl_conf) is True
|
|
|
|
|
assert crypto_util.sha256sum(self.config.mod_ssl_conf) == \
|
|
|
|
|
self._current_ssl_options_hash()
|
2017-05-23 19:25:39 -04:00
|
|
|
|
|
|
|
|
def test_no_file(self):
|
|
|
|
|
# prepare should have placed a file there
|
|
|
|
|
self._assert_current_file()
|
|
|
|
|
os.remove(self.config.mod_ssl_conf)
|
2023-02-16 00:02:02 -05:00
|
|
|
assert os.path.isfile(self.config.mod_ssl_conf) is False
|
2017-05-23 19:25:39 -04:00
|
|
|
self._call()
|
|
|
|
|
self._assert_current_file()
|
|
|
|
|
|
|
|
|
|
def test_current_file(self):
|
|
|
|
|
self._assert_current_file()
|
|
|
|
|
self._call()
|
|
|
|
|
self._assert_current_file()
|
|
|
|
|
|
|
|
|
|
def test_prev_file_updates_to_current(self):
|
2019-11-25 12:44:40 -05:00
|
|
|
from certbot_apache._internal.constants import ALL_SSL_OPTIONS_HASHES
|
2017-05-23 19:25:39 -04:00
|
|
|
ALL_SSL_OPTIONS_HASHES.insert(0, "test_hash_does_not_match")
|
|
|
|
|
with mock.patch('certbot.crypto_util.sha256sum') as mock_sha256:
|
|
|
|
|
mock_sha256.return_value = ALL_SSL_OPTIONS_HASHES[0]
|
|
|
|
|
self._call()
|
|
|
|
|
self._assert_current_file()
|
|
|
|
|
|
|
|
|
|
def test_manually_modified_current_file_does_not_update(self):
|
|
|
|
|
with open(self.config.mod_ssl_conf, "a") as mod_ssl_conf:
|
|
|
|
|
mod_ssl_conf.write("a new line for the wrong hash\n")
|
2017-06-01 12:12:50 -04:00
|
|
|
with mock.patch("certbot.plugins.common.logger") as mock_logger:
|
2017-05-23 19:25:39 -04:00
|
|
|
self._call()
|
2023-02-16 00:02:02 -05:00
|
|
|
assert mock_logger.warning.called is False
|
|
|
|
|
assert os.path.isfile(self.config.mod_ssl_conf) is True
|
|
|
|
|
assert crypto_util.sha256sum(
|
|
|
|
|
self.config.pick_apache_config()) == \
|
|
|
|
|
self._current_ssl_options_hash()
|
|
|
|
|
assert crypto_util.sha256sum(self.config.mod_ssl_conf) != \
|
|
|
|
|
self._current_ssl_options_hash()
|
2017-05-23 19:25:39 -04:00
|
|
|
|
|
|
|
|
def test_manually_modified_past_file_warns(self):
|
|
|
|
|
with open(self.config.mod_ssl_conf, "a") as mod_ssl_conf:
|
|
|
|
|
mod_ssl_conf.write("a new line for the wrong hash\n")
|
|
|
|
|
with open(self.config.updated_mod_ssl_conf_digest, "w") as f:
|
|
|
|
|
f.write("hashofanoldversion")
|
2017-06-01 12:12:50 -04:00
|
|
|
with mock.patch("certbot.plugins.common.logger") as mock_logger:
|
2017-05-23 19:25:39 -04:00
|
|
|
self._call()
|
2023-02-16 00:02:02 -05:00
|
|
|
assert mock_logger.warning.call_args[0][0] == \
|
|
|
|
|
"%s has been manually modified; updated file " \
|
|
|
|
|
"saved to %s. We recommend updating %s for security purposes."
|
|
|
|
|
assert crypto_util.sha256sum(
|
|
|
|
|
self.config.pick_apache_config()) == \
|
|
|
|
|
self._current_ssl_options_hash()
|
2017-05-23 19:25:39 -04:00
|
|
|
# only print warning once
|
2017-06-01 12:12:50 -04:00
|
|
|
with mock.patch("certbot.plugins.common.logger") as mock_logger:
|
2017-05-23 19:25:39 -04:00
|
|
|
self._call()
|
2023-02-16 00:02:02 -05:00
|
|
|
assert mock_logger.warning.called is False
|
2017-05-23 19:25:39 -04:00
|
|
|
|
2020-03-23 19:49:52 -04:00
|
|
|
def test_ssl_config_files_hash_in_all_hashes(self):
|
|
|
|
|
"""
|
|
|
|
|
It is really critical that all TLS Apache config files have their SHA256 hash registered in
|
|
|
|
|
constants.ALL_SSL_OPTIONS_HASHES. Otherwise Certbot will mistakenly assume that the config
|
|
|
|
|
file has been manually edited by the user, and will refuse to update it.
|
|
|
|
|
This test ensures that all necessary hashes are present.
|
|
|
|
|
"""
|
2023-09-07 14:38:44 -04:00
|
|
|
if sys.version_info >= (3, 9): # pragma: no cover
|
|
|
|
|
import importlib.resources as importlib_resources
|
|
|
|
|
else: # pragma: no cover
|
|
|
|
|
import importlib_resources
|
2020-03-23 19:49:52 -04:00
|
|
|
|
2023-02-10 13:51:20 -05:00
|
|
|
from certbot_apache._internal.constants import ALL_SSL_OPTIONS_HASHES
|
|
|
|
|
|
2023-09-07 14:38:44 -04:00
|
|
|
ref = importlib_resources.files("certbot_apache") / "_internal" / "tls_configs"
|
|
|
|
|
with importlib_resources.as_file(ref) as tls_configs_dir:
|
|
|
|
|
all_files = [os.path.join(tls_configs_dir, name) for name in os.listdir(tls_configs_dir)
|
|
|
|
|
if name.endswith('options-ssl-apache.conf')]
|
|
|
|
|
assert len(all_files) >= 1
|
|
|
|
|
for one_file in all_files:
|
|
|
|
|
file_hash = crypto_util.sha256sum(one_file)
|
|
|
|
|
assert file_hash in ALL_SSL_OPTIONS_HASHES, \
|
|
|
|
|
f"Constants.ALL_SSL_OPTIONS_HASHES must be appended with the sha256 " \
|
|
|
|
|
f"hash of {one_file} when it is updated."
|
2020-03-23 19:49:52 -04:00
|
|
|
|
|
|
|
|
def test_openssl_version(self):
|
|
|
|
|
self.config._openssl_version = None
|
|
|
|
|
some_string_contents = b"""
|
|
|
|
|
SSLOpenSSLConfCmd
|
|
|
|
|
OpenSSL configuration command
|
|
|
|
|
SSLv3 not supported by this version of OpenSSL
|
|
|
|
|
'%s': invalid OpenSSL configuration command
|
|
|
|
|
OpenSSL 1.0.2g 1 Mar 2016
|
|
|
|
|
OpenSSL
|
|
|
|
|
AH02407: "SSLOpenSSLConfCmd %s %s" failed for %s
|
|
|
|
|
AH02556: "SSLOpenSSLConfCmd %s %s" applied to %s
|
|
|
|
|
OpenSSL 1.0.2g 1 Mar 2016
|
|
|
|
|
"""
|
2020-06-04 13:34:10 -04:00
|
|
|
# ssl_module as a DSO
|
2020-03-23 19:49:52 -04:00
|
|
|
self.config.parser.modules['ssl_module'] = '/fake/path'
|
|
|
|
|
with mock.patch("certbot_apache._internal.configurator."
|
|
|
|
|
"ApacheConfigurator._open_module_file") as mock_omf:
|
|
|
|
|
mock_omf.return_value = some_string_contents
|
2023-02-16 00:02:02 -05:00
|
|
|
assert self.config.openssl_version() == "1.0.2g"
|
2020-03-23 19:49:52 -04:00
|
|
|
|
2020-06-04 13:34:10 -04:00
|
|
|
# ssl_module statically linked
|
|
|
|
|
self.config._openssl_version = None
|
|
|
|
|
self.config.parser.modules['ssl_module'] = None
|
2021-04-13 14:18:49 -04:00
|
|
|
self.config.options.bin = '/fake/path/to/httpd'
|
2020-06-04 13:34:10 -04:00
|
|
|
with mock.patch("certbot_apache._internal.configurator."
|
|
|
|
|
"ApacheConfigurator._open_module_file") as mock_omf:
|
|
|
|
|
mock_omf.return_value = some_string_contents
|
2023-02-16 00:02:02 -05:00
|
|
|
assert self.config.openssl_version() == "1.0.2g"
|
2020-06-04 13:34:10 -04:00
|
|
|
|
2020-03-23 19:49:52 -04:00
|
|
|
def test_current_version(self):
|
|
|
|
|
self.config.version = (2, 4, 10)
|
|
|
|
|
self.config._openssl_version = '1.0.2m'
|
2023-02-16 00:02:02 -05:00
|
|
|
assert 'old' in self.config.pick_apache_config()
|
2020-03-23 19:49:52 -04:00
|
|
|
|
|
|
|
|
self.config.version = (2, 4, 11)
|
|
|
|
|
self.config._openssl_version = '1.0.2m'
|
2023-02-16 00:02:02 -05:00
|
|
|
assert 'current' in self.config.pick_apache_config()
|
2020-03-23 19:49:52 -04:00
|
|
|
|
|
|
|
|
self.config._openssl_version = '1.0.2a'
|
2023-02-16 00:02:02 -05:00
|
|
|
assert 'old' in self.config.pick_apache_config()
|
2020-03-23 19:49:52 -04:00
|
|
|
|
|
|
|
|
def test_openssl_version_warns(self):
|
|
|
|
|
self.config._openssl_version = '1.0.2a'
|
2023-02-16 00:02:02 -05:00
|
|
|
assert self.config.openssl_version() == '1.0.2a'
|
2020-03-23 19:49:52 -04:00
|
|
|
|
|
|
|
|
self.config._openssl_version = None
|
|
|
|
|
with mock.patch("certbot_apache._internal.configurator.logger.warning") as mock_log:
|
2023-02-16 00:02:02 -05:00
|
|
|
assert self.config.openssl_version() == None
|
|
|
|
|
assert "Could not find ssl_module" in mock_log.call_args[0][0]
|
2020-03-23 19:49:52 -04:00
|
|
|
|
2020-06-04 13:34:10 -04:00
|
|
|
# When no ssl_module is present at all
|
2020-03-23 19:49:52 -04:00
|
|
|
self.config._openssl_version = None
|
2023-02-16 00:02:02 -05:00
|
|
|
assert "ssl_module" not in self.config.parser.modules
|
2020-03-23 19:49:52 -04:00
|
|
|
with mock.patch("certbot_apache._internal.configurator.logger.warning") as mock_log:
|
2023-02-16 00:02:02 -05:00
|
|
|
assert self.config.openssl_version() == None
|
|
|
|
|
assert "Could not find ssl_module" in mock_log.call_args[0][0]
|
2017-05-23 19:25:39 -04:00
|
|
|
|
2020-06-04 13:34:10 -04:00
|
|
|
# When ssl_module is statically linked but --apache-bin not provided
|
|
|
|
|
self.config._openssl_version = None
|
2021-04-13 14:18:49 -04:00
|
|
|
self.config.options.bin = None
|
2020-06-04 13:34:10 -04:00
|
|
|
self.config.parser.modules['ssl_module'] = None
|
|
|
|
|
with mock.patch("certbot_apache._internal.configurator.logger.warning") as mock_log:
|
2023-02-16 00:02:02 -05:00
|
|
|
assert self.config.openssl_version() == None
|
|
|
|
|
assert "ssl_module is statically linked but" in mock_log.call_args[0][0]
|
2020-06-04 13:34:10 -04:00
|
|
|
|
2020-03-23 19:49:52 -04:00
|
|
|
self.config.parser.modules['ssl_module'] = "/fake/path"
|
|
|
|
|
with mock.patch("certbot_apache._internal.configurator.logger.warning") as mock_log:
|
|
|
|
|
# Check that correct logger.warning was printed
|
2023-02-16 00:02:02 -05:00
|
|
|
assert self.config.openssl_version() == None
|
|
|
|
|
assert "Unable to read" in mock_log.call_args[0][0]
|
2020-03-23 19:49:52 -04:00
|
|
|
|
|
|
|
|
contents_missing_openssl = b"these contents won't match the regex"
|
|
|
|
|
with mock.patch("certbot_apache._internal.configurator."
|
|
|
|
|
"ApacheConfigurator._open_module_file") as mock_omf:
|
|
|
|
|
mock_omf.return_value = contents_missing_openssl
|
|
|
|
|
with mock.patch("certbot_apache._internal.configurator.logger.warning") as mock_log:
|
|
|
|
|
# Check that correct logger.warning was printed
|
2023-02-16 00:02:02 -05:00
|
|
|
assert self.config.openssl_version() == None
|
|
|
|
|
assert "Could not find OpenSSL" in mock_log.call_args[0][0]
|
2020-03-23 19:49:52 -04:00
|
|
|
|
|
|
|
|
def test_open_module_file(self):
|
|
|
|
|
mock_open = mock.mock_open(read_data="testing 12 3")
|
2021-02-09 14:43:15 -05:00
|
|
|
with mock.patch("builtins.open", mock_open):
|
2023-02-16 00:02:02 -05:00
|
|
|
assert self.config._open_module_file("/nonsense/") == "testing 12 3"
|
2017-05-23 19:25:39 -04:00
|
|
|
|
2015-03-26 20:39:08 -04:00
|
|
|
if __name__ == "__main__":
|
2023-02-13 14:44:42 -05:00
|
|
|
sys.exit(pytest.main(sys.argv[1:] + [__file__])) # pragma: no cover
|