certbot/certbot-apache/certbot_apache/tests/parser_test.py

239 lines
8.6 KiB
Python
Raw Normal View History

"""Tests for certbot_apache.parser."""
2014-12-19 18:49:29 -05:00
import os
import shutil
import unittest
import augeas
import mock
from certbot import errors
2015-07-23 04:34:51 -04:00
from certbot_apache.tests import util
2014-12-19 18:49:29 -05:00
2015-07-19 19:48:27 -04:00
class BasicParserTest(util.ParserTest):
2015-01-24 08:12:45 -05:00
"""Apache Parser Test."""
2014-12-19 18:49:29 -05:00
2015-07-19 19:48:27 -04:00
def setUp(self): # pylint: disable=arguments-differ
super(BasicParserTest, self).setUp()
2014-12-19 18:49:29 -05:00
def tearDown(self):
shutil.rmtree(self.temp_dir)
shutil.rmtree(self.config_dir)
shutil.rmtree(self.work_dir)
2015-07-24 20:05:25 -04:00
def test_find_config_root_no_root(self):
# pylint: disable=protected-access
os.remove(self.parser.loc["root"])
self.assertRaises(
errors.NoInstallationError, self.parser._find_config_root)
2014-12-19 18:49:29 -05:00
def test_parse_file(self):
"""Test parse_file.
certbot.conf is chosen as the test file as it will not be
2014-12-19 18:49:29 -05:00
included during the normal course of execution.
"""
file_path = os.path.join(
self.config_path, "not-parsed-by-default", "certbot.conf")
2014-12-19 18:49:29 -05:00
Do not parse disabled configuration files from under sites-available on Debian / Ubuntu (#4104) This changes the apache plugin behaviour to only parse enabled configuration files and respecting the --apache-vhost-root CLI parameter for new SSL vhost creation. If --apache-vhost-root isn't defined, or doesn't exist, the SSL vhost will be created to originating non-SSL vhost directory. This PR also implements actual check for vhost enabled state, and makes sure parser.parse_file() does not discard changes in Augeas DOM, by doing an autosave. Also handles enabling the new SSL vhost, if it's on a path that's not parsed by Apache. Fixes: #1328 Fixes: #3545 Fixes: #3791 Fixes: #4523 Fixes: #4837 Fixes: #4905 * First changes * Handle rest of the errors * Test fixes * Final fixes * Make parse_files accessible and fix linter problems * Activate vhost at later time * Cleanup * Add a new test case, and fix old * Enable site later in deploy_cert * Make apache-conf-test default dummy configuration enabled * Remove is_sites_available as obsolete * Cleanup * Brought back conditional vhost_path parsing * Parenthesis * Fix merge leftovers * Fix to work with the recent changes to new file creation * Added fix and tests for non-symlink vhost in sites-enabled * Made vhostroot parameter for ApacheParser optional, and removed extra_path * Respect vhost-root, and add Include statements to root configuration if needed * Fixed site enabling order to prevent apache restart error while enabling mod_ssl * Don't exclude Ubuntu / Debian vhost-root cli argument * Changed the SSL vhost directory selection priority * Requested fixes for paths and vhost discovery * Make sure the Augeas DOM is written to disk before loading new files * Actual checking for if the file is parsed within existing Apache configuration * Fix the order of dummy SSL directives addition and enabling modules * Restructured site_enabled checks * Enabling vhost correctly for non-debian systems
2017-09-25 15:03:09 -04:00
self.parser.parse_file(file_path) # pylint: disable=protected-access
2014-12-19 18:49:29 -05:00
# search for the httpd incl
matches = self.parser.aug.match(
"/augeas/load/Httpd/incl [. ='%s']" % file_path)
self.assertTrue(matches)
def test_find_dir(self):
2015-07-19 05:22:10 -04:00
test = self.parser.find_dir("Listen", "80")
2014-12-19 18:49:29 -05:00
# This will only look in enabled hosts
2015-07-19 05:22:10 -04:00
test2 = self.parser.find_dir("documentroot")
self.assertEqual(len(test), 1)
Do not parse disabled configuration files from under sites-available on Debian / Ubuntu (#4104) This changes the apache plugin behaviour to only parse enabled configuration files and respecting the --apache-vhost-root CLI parameter for new SSL vhost creation. If --apache-vhost-root isn't defined, or doesn't exist, the SSL vhost will be created to originating non-SSL vhost directory. This PR also implements actual check for vhost enabled state, and makes sure parser.parse_file() does not discard changes in Augeas DOM, by doing an autosave. Also handles enabling the new SSL vhost, if it's on a path that's not parsed by Apache. Fixes: #1328 Fixes: #3545 Fixes: #3791 Fixes: #4523 Fixes: #4837 Fixes: #4905 * First changes * Handle rest of the errors * Test fixes * Final fixes * Make parse_files accessible and fix linter problems * Activate vhost at later time * Cleanup * Add a new test case, and fix old * Enable site later in deploy_cert * Make apache-conf-test default dummy configuration enabled * Remove is_sites_available as obsolete * Cleanup * Brought back conditional vhost_path parsing * Parenthesis * Fix merge leftovers * Fix to work with the recent changes to new file creation * Added fix and tests for non-symlink vhost in sites-enabled * Made vhostroot parameter for ApacheParser optional, and removed extra_path * Respect vhost-root, and add Include statements to root configuration if needed * Fixed site enabling order to prevent apache restart error while enabling mod_ssl * Don't exclude Ubuntu / Debian vhost-root cli argument * Changed the SSL vhost directory selection priority * Requested fixes for paths and vhost discovery * Make sure the Augeas DOM is written to disk before loading new files * Actual checking for if the file is parsed within existing Apache configuration * Fix the order of dummy SSL directives addition and enabling modules * Restructured site_enabled checks * Enabling vhost correctly for non-debian systems
2017-09-25 15:03:09 -04:00
self.assertEqual(len(test2), 7)
2014-12-19 18:49:29 -05:00
def test_add_dir(self):
aug_default = "/files" + self.parser.loc["default"]
2014-12-20 06:43:39 -05:00
self.parser.add_dir(aug_default, "AddDirective", "test")
2014-12-19 18:49:29 -05:00
self.assertTrue(
self.parser.find_dir("AddDirective", "test", aug_default))
self.parser.add_dir(aug_default, "AddList", ["1", "2", "3", "4"])
matches = self.parser.find_dir("AddList", None, aug_default)
for i, match in enumerate(matches):
self.assertEqual(self.parser.aug.get(match), str(i + 1))
def test_empty_arg(self):
self.assertEquals(None,
self.parser.get_arg("/files/whatever/nonexistent"))
2014-12-19 18:49:29 -05:00
def test_add_dir_to_ifmodssl(self):
"""test add_dir_to_ifmodssl.
Path must be valid before attempting to add to augeas
"""
from certbot_apache.parser import get_aug_path
2015-07-19 05:22:10 -04:00
# This makes sure that find_dir will work
self.parser.modules.add("mod_ssl.c")
2014-12-19 18:49:29 -05:00
self.parser.add_dir_to_ifmodssl(
get_aug_path(self.parser.loc["default"]),
2015-07-17 17:09:46 -04:00
"FakeDirective", ["123"])
2014-12-19 18:49:29 -05:00
matches = self.parser.find_dir("FakeDirective", "123")
self.assertEqual(len(matches), 1)
self.assertTrue("IfModule" in matches[0])
2015-07-23 04:34:51 -04:00
def test_add_dir_to_ifmodssl_multiple(self):
from certbot_apache.parser import get_aug_path
2015-07-23 04:34:51 -04:00
# This makes sure that find_dir will work
self.parser.modules.add("mod_ssl.c")
self.parser.add_dir_to_ifmodssl(
get_aug_path(self.parser.loc["default"]),
"FakeDirective", ["123", "456", "789"])
matches = self.parser.find_dir("FakeDirective")
self.assertEqual(len(matches), 3)
self.assertTrue("IfModule" in matches[0])
2014-12-19 18:49:29 -05:00
def test_get_aug_path(self):
from certbot_apache.parser import get_aug_path
self.assertEqual("/files/etc/apache", get_aug_path("/etc/apache"))
2014-12-19 18:49:29 -05:00
def test_set_locations(self):
with mock.patch("certbot_apache.parser.os.path") as mock_path:
2014-12-19 18:49:29 -05:00
2016-01-26 14:40:44 -05:00
mock_path.isfile.side_effect = [False, False]
2014-12-19 18:49:29 -05:00
# pylint: disable=protected-access
2015-07-23 04:34:51 -04:00
results = self.parser._set_locations()
2014-12-19 18:49:29 -05:00
self.assertEqual(results["default"], results["listen"])
self.assertEqual(results["default"], results["name"])
2015-01-24 08:12:45 -05:00
@mock.patch("certbot_apache.parser.ApacheParser.find_dir")
@mock.patch("certbot_apache.parser.ApacheParser.get_arg")
def test_init_modules_bad_syntax(self, mock_arg, mock_find):
mock_find.return_value = ["1", "2", "3", "4", "5", "6", "7", "8"]
mock_arg.return_value = None
with mock.patch("certbot_apache.parser.logger") as mock_logger:
self.parser.init_modules()
# Make sure that we got None return value and logged the file
self.assertTrue(mock_logger.debug.called)
@mock.patch("certbot_apache.parser.ApacheParser._get_runtime_cfg")
2015-07-23 04:34:51 -04:00
def test_update_runtime_variables(self, mock_cfg):
mock_cfg.return_value = (
'ServerRoot: "/etc/apache2"\n'
'Main DocumentRoot: "/var/www"\n'
'Main ErrorLog: "/var/log/apache2/error.log"\n'
'Mutex ssl-stapling: using_defaults\n'
'Mutex ssl-cache: using_defaults\n'
'Mutex default: dir="/var/lock/apache2" mechanism=fcntl\n'
'Mutex watchdog-callback: using_defaults\n'
'PidFile: "/var/run/apache2/apache2.pid"\n'
'Define: TEST\n'
'Define: DUMP_RUN_CFG\n'
'Define: U_MICH\n'
'Define: TLS=443\n'
'Define: example_path=Documents/path\n'
'User: name="www-data" id=33 not_used\n'
'Group: name="www-data" id=33 not_used\n'
)
expected_vars = {"TEST": "", "U_MICH": "", "TLS": "443",
2015-09-06 04:21:29 -04:00
"example_path": "Documents/path"}
2015-07-23 04:34:51 -04:00
2015-12-28 07:03:50 -05:00
self.parser.update_runtime_variables()
2015-07-23 04:34:51 -04:00
self.assertEqual(self.parser.variables, expected_vars)
@mock.patch("certbot_apache.parser.ApacheParser._get_runtime_cfg")
2015-07-23 04:34:51 -04:00
def test_update_runtime_vars_bad_output(self, mock_cfg):
mock_cfg.return_value = "Define: TLS=443=24"
2015-12-28 07:03:50 -05:00
self.parser.update_runtime_variables()
2015-07-23 04:34:51 -04:00
mock_cfg.return_value = "Define: DUMP_RUN_CFG\nDefine: TLS=443=24"
self.assertRaises(
2015-12-28 07:03:50 -05:00
errors.PluginError, self.parser.update_runtime_variables)
2015-07-23 04:34:51 -04:00
@mock.patch("certbot_apache.constants.os_constant")
@mock.patch("certbot_apache.parser.subprocess.Popen")
2015-12-28 07:03:50 -05:00
def test_update_runtime_vars_bad_ctl(self, mock_popen, mock_const):
2015-07-23 04:34:51 -04:00
mock_popen.side_effect = OSError
2015-12-28 07:03:50 -05:00
mock_const.return_value = "nonexistent"
2015-07-23 04:34:51 -04:00
self.assertRaises(
errors.MisconfigurationError,
2015-12-28 07:03:50 -05:00
self.parser.update_runtime_variables)
2015-07-23 04:34:51 -04:00
@mock.patch("certbot_apache.parser.subprocess.Popen")
2015-07-23 04:34:51 -04:00
def test_update_runtime_vars_bad_exit(self, mock_popen):
mock_popen().communicate.return_value = ("", "")
mock_popen.returncode = -1
self.assertRaises(
errors.MisconfigurationError,
2015-12-28 07:03:50 -05:00
self.parser.update_runtime_variables)
2015-07-23 04:34:51 -04:00
2015-01-24 08:12:45 -05:00
2015-07-15 18:25:34 -04:00
class ParserInitTest(util.ApacheTest):
2015-07-19 19:48:27 -04:00
def setUp(self): # pylint: disable=arguments-differ
2015-07-15 18:25:34 -04:00
super(ParserInitTest, self).setUp()
self.aug = augeas.Augeas(
flags=augeas.Augeas.NONE | augeas.Augeas.NO_MODL_AUTOLOAD)
def tearDown(self):
shutil.rmtree(self.temp_dir)
shutil.rmtree(self.config_dir)
shutil.rmtree(self.work_dir)
@mock.patch("certbot_apache.parser.ApacheParser._get_runtime_cfg")
def test_unparseable(self, mock_cfg):
from certbot_apache.parser import ApacheParser
2015-12-23 13:08:44 -05:00
mock_cfg.return_value = ('Define: TEST')
self.assertRaises(
errors.PluginError,
ApacheParser, self.aug, os.path.relpath(self.config_path),
2015-12-28 07:03:50 -05:00
"/dummy/vhostpath", version=(2, 2, 22))
2015-12-09 21:51:16 -05:00
2015-07-15 18:25:34 -04:00
def test_root_normalized(self):
from certbot_apache.parser import ApacheParser
2015-07-15 18:25:34 -04:00
with mock.patch("certbot_apache.parser.ApacheParser."
2015-07-15 18:25:34 -04:00
"update_runtime_variables"):
path = os.path.join(
self.temp_dir,
"debian_apache_2_4/////multiple_vhosts/../multiple_vhosts/apache2")
2015-12-07 05:03:54 -05:00
parser = ApacheParser(self.aug, path,
2015-12-28 07:03:50 -05:00
"/dummy/vhostpath")
2015-07-15 18:25:34 -04:00
self.assertEqual(parser.root, self.config_path)
def test_root_absolute(self):
from certbot_apache.parser import ApacheParser
with mock.patch("certbot_apache.parser.ApacheParser."
2015-07-15 18:25:34 -04:00
"update_runtime_variables"):
parser = ApacheParser(
2015-12-07 05:03:54 -05:00
self.aug, os.path.relpath(self.config_path),
2015-12-28 07:03:50 -05:00
"/dummy/vhostpath")
2015-07-15 18:25:34 -04:00
self.assertEqual(parser.root, self.config_path)
def test_root_no_trailing_slash(self):
from certbot_apache.parser import ApacheParser
with mock.patch("certbot_apache.parser.ApacheParser."
2015-07-15 18:25:34 -04:00
"update_runtime_variables"):
parser = ApacheParser(
2015-12-07 05:03:54 -05:00
self.aug, self.config_path + os.path.sep,
2015-12-28 07:03:50 -05:00
"/dummy/vhostpath")
2015-07-15 18:25:34 -04:00
self.assertEqual(parser.root, self.config_path)
2015-07-19 22:49:44 -04:00
2015-03-26 20:39:08 -04:00
if __name__ == "__main__":
unittest.main() # pragma: no cover