diff --git a/.pylintrc b/.pylintrc
index d510fddfd..36d8c286f 100644
--- a/.pylintrc
+++ b/.pylintrc
@@ -41,7 +41,7 @@ load-plugins=linter_plugin
# --enable=similarities". If you want to run only the classes checker, but have
# no Warning level messages displayed, use"--disable=all --enable=classes
# --disable=W"
-disable=fixme,locally-disabled,abstract-class-not-used,abstract-class-little-used,bad-continuation,too-few-public-methods,no-self-use,invalid-name,too-many-instance-attributes,cyclic-import
+disable=fixme,locally-disabled,abstract-class-not-used,abstract-class-little-used,bad-continuation,too-few-public-methods,no-self-use,invalid-name,too-many-instance-attributes,cyclic-import,duplicate-code
# abstract-class-not-used cannot be disabled locally (at least in
# pylint 1.4.1), same for abstract-class-little-used
diff --git a/certbot-apache/certbot_apache/apache_util.py b/certbot-apache/certbot_apache/apache_util.py
new file mode 100644
index 000000000..b4a24f137
--- /dev/null
+++ b/certbot-apache/certbot_apache/apache_util.py
@@ -0,0 +1,96 @@
+""" Utility functions for certbot-apache plugin """
+import os
+
+from certbot import util
+
+def get_mod_deps(mod_name):
+ """Get known module dependencies.
+
+ .. note:: This does not need to be accurate in order for the client to
+ run. This simply keeps things clean if the user decides to revert
+ changes.
+ .. warning:: If all deps are not included, it may cause incorrect parsing
+ behavior, due to enable_mod's shortcut for updating the parser's
+ currently defined modules (`.ApacheParser.add_mod`)
+ This would only present a major problem in extremely atypical
+ configs that use ifmod for the missing deps.
+
+ """
+ deps = {
+ "ssl": ["setenvif", "mime"]
+ }
+ return deps.get(mod_name, [])
+
+
+def get_file_path(vhost_path):
+ """Get file path from augeas_vhost_path.
+
+ Takes in Augeas path and returns the file name
+
+ :param str vhost_path: Augeas virtual host path
+
+ :returns: filename of vhost
+ :rtype: str
+
+ """
+ if not vhost_path or not vhost_path.startswith("/files/"):
+ return None
+
+ return _split_aug_path(vhost_path)[0]
+
+
+def get_internal_aug_path(vhost_path):
+ """Get the Augeas path for a vhost with the file path removed.
+
+ :param str vhost_path: Augeas virtual host path
+
+ :returns: Augeas path to vhost relative to the containing file
+ :rtype: str
+
+ """
+ return _split_aug_path(vhost_path)[1]
+
+
+def _split_aug_path(vhost_path):
+ """Splits an Augeas path into a file path and an internal path.
+
+ After removing "/files", this function splits vhost_path into the
+ file path and the remaining Augeas path.
+
+ :param str vhost_path: Augeas virtual host path
+
+ :returns: file path and internal Augeas path
+ :rtype: `tuple` of `str`
+
+ """
+ # Strip off /files
+ file_path = vhost_path[6:]
+ internal_path = []
+
+ # Remove components from the end of file_path until it becomes valid
+ while not os.path.exists(file_path):
+ file_path, _, internal_path_part = file_path.rpartition("/")
+ internal_path.append(internal_path_part)
+
+ return file_path, "/".join(reversed(internal_path))
+
+
+def parse_define_file(filepath, varname):
+ """ Parses Defines from a variable in configuration file
+
+ :param str filepath: Path of file to parse
+ :param str varname: Name of the variable
+
+ :returns: Dict of Define:Value pairs
+ :rtype: `dict`
+
+ """
+ return_vars = {}
+ # Get list of words in the variable
+ a_opts = util.get_var_from_file(varname, filepath).split()
+ for i, v in enumerate(a_opts):
+ # Handle Define statements and make sure it has an argument
+ if v == "-D" and len(a_opts) >= i+2:
+ var_parts = a_opts[i+1].partition("=")
+ return_vars[var_parts[0]] = var_parts[2]
+ return return_vars
diff --git a/certbot-apache/certbot_apache/configurator.py b/certbot-apache/certbot_apache/configurator.py
index 8b6c578d6..5a33346ea 100644
--- a/certbot-apache/certbot_apache/configurator.py
+++ b/certbot-apache/certbot_apache/configurator.py
@@ -3,6 +3,7 @@
import fnmatch
import logging
import os
+import pkg_resources
import re
import socket
import time
@@ -19,6 +20,7 @@ from certbot import util
from certbot.plugins import common
from certbot.plugins.util import path_surgery
+from certbot_apache import apache_util
from certbot_apache import augeas_configurator
from certbot_apache import constants
from certbot_apache import display_ops
@@ -85,27 +87,50 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
description = "Apache Web Server plugin - Beta"
+ OS_DEFAULTS = dict(
+ server_root="/etc/apache2",
+ vhost_root="/etc/apache2/sites-available",
+ vhost_files="*",
+ logs_root="/var/log/apache2",
+ version_cmd=['apache2ctl', '-v'],
+ apache_cmd="apache2ctl",
+ restart_cmd=['apache2ctl', 'graceful'],
+ conftest_cmd=['apache2ctl', 'configtest'],
+ enmod=None,
+ dismod=None,
+ le_vhost_ext="-le-ssl.conf",
+ handle_mods=False,
+ handle_sites=False,
+ challenge_location="/etc/apache2",
+ MOD_SSL_CONF_SRC=pkg_resources.resource_filename(
+ "certbot_apache", "options-ssl-apache.conf")
+ )
+
+ def constant(self, key):
+ """Get constant for OS_DEFAULTS"""
+ return self.OS_DEFAULTS.get(key)
+
@classmethod
def add_parser_arguments(cls, add):
- add("enmod", default=constants.os_constant("enmod"),
+ add("enmod", default=cls.OS_DEFAULTS["enmod"],
help="Path to the Apache 'a2enmod' binary.")
- add("dismod", default=constants.os_constant("dismod"),
+ add("dismod", default=cls.OS_DEFAULTS["dismod"],
help="Path to the Apache 'a2dismod' binary.")
- add("le-vhost-ext", default=constants.os_constant("le_vhost_ext"),
+ add("le-vhost-ext", default=cls.OS_DEFAULTS["le_vhost_ext"],
help="SSL vhost configuration extension.")
- add("server-root", default=constants.os_constant("server_root"),
+ add("server-root", default=cls.OS_DEFAULTS["server_root"],
help="Apache server root directory.")
add("vhost-root", default=None,
help="Apache server VirtualHost configuration root")
- add("logs-root", default=constants.os_constant("logs_root"),
+ add("logs-root", default=cls.OS_DEFAULTS["logs_root"],
help="Apache server logs directory")
add("challenge-location",
- default=constants.os_constant("challenge_location"),
+ default=cls.OS_DEFAULTS["challenge_location"],
help="Directory path for challenge configuration.")
- add("handle-modules", default=constants.os_constant("handle_mods"),
+ add("handle-modules", default=cls.OS_DEFAULTS["handle_mods"],
help="Let installer handle enabling required modules for you." +
"(Only Ubuntu/Debian currently)")
- add("handle-sites", default=constants.os_constant("handle_sites"),
+ add("handle-sites", default=cls.OS_DEFAULTS["handle_sites"],
help="Let installer handle enabling sites for you." +
"(Only Ubuntu/Debian currently)")
util.add_deprecated_argument(add, argument_name="ctl", nargs=1)
@@ -166,7 +191,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
raise errors.NoInstallationError("Problem in Augeas installation")
# Verify Apache is installed
- restart_cmd = constants.os_constant("restart_cmd")[0]
+ restart_cmd = self.constant("restart_cmd")[0]
if not util.exe_exists(restart_cmd):
if not path_surgery(restart_cmd):
raise errors.NoInstallationError(
@@ -192,20 +217,20 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
# Parse vhost-root if defined on cli
if not self.conf("vhost-root"):
- self.vhostroot = constants.os_constant("vhost_root")
+ self.vhostroot = self.constant("vhost_root")
else:
self.vhostroot = os.path.abspath(self.conf("vhost-root"))
- self.parser = parser.ApacheParser(
- self.aug, self.conf("server-root"), self.conf("vhost-root"),
- self.version, configurator=self)
+ self.parser = self.get_parser()
+
# Check for errors in parsing files with Augeas
self.check_parsing_errors("httpd.aug")
# Get all of the available vhosts
self.vhosts = self.get_virtual_hosts()
- install_ssl_options_conf(self.mod_ssl_conf, self.updated_mod_ssl_conf_digest)
+ self.install_ssl_options_conf(self.mod_ssl_conf,
+ self.updated_mod_ssl_conf_digest)
# Prevent two Apache plugins from modifying a config at once
try:
@@ -230,6 +255,12 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
self.aug.remove("/test/path")
return matches
+ def get_parser(self):
+ """Initializes the ApacheParser"""
+ return parser.ApacheParser(
+ self.aug, self.conf("server-root"), self.conf("vhost-root"),
+ self.version, configurator=self)
+
def deploy_cert(self, domain, cert_path, key_path,
chain_path=None, fullchain_path=None):
"""Deploys certificate to specified virtual host.
@@ -585,7 +616,8 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
if addr.get_port() == "443":
is_ssl = True
- filename = get_file_path(self.aug.get("/augeas/files%s/path" % get_file_path(path)))
+ filename = apache_util.get_file_path(
+ self.aug.get("/augeas/files%s/path" % apache_util.get_file_path(path)))
if filename is None:
return None
@@ -624,7 +656,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
new_vhost = self._create_vhost(path)
if not new_vhost:
continue
- internal_path = get_internal_aug_path(new_vhost.path)
+ internal_path = apache_util.get_internal_aug_path(new_vhost.path)
realpath = os.path.realpath(new_vhost.filep)
if realpath not in file_paths:
file_paths[realpath] = new_vhost.filep
@@ -640,7 +672,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
for v in vhs:
if v.filep == file_paths[realpath]:
internal_paths[realpath].remove(
- get_internal_aug_path(v.path))
+ apache_util.get_internal_aug_path(v.path))
else:
new_vhs.append(v)
vhs = new_vhs
@@ -828,7 +860,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
Duplicates vhost and adds default ssl options
New vhost will reside as (nonssl_vhost.path) +
- ``certbot_apache.constants.os_constant("le_vhost_ext")``
+ ``self.constant("le_vhost_ext")``
.. note:: This function saves the configuration
@@ -1702,17 +1734,13 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
return redirects
-
def enable_site(self, vhost):
"""Enables an available site, Apache reload required.
.. note:: Does not make sure that the site correctly works or that all
modules are enabled appropriately.
-
- .. todo:: This function should number subdomains before the domain
- vhost
-
- .. todo:: Make sure link is not broken...
+ .. note:: The distribution specific override replaces functionality
+ of this method where available.
:param vhost: vhost to enable
:type vhost: :class:`~certbot_apache.obj.VirtualHost`
@@ -1724,39 +1752,16 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
if vhost.enabled:
return
- # Handle non-debian systems
- if not self.conf("handle-sites"):
- if not self.parser.parsed_in_original(vhost.filep):
- # Add direct include to root conf
- self.parser.add_include(self.parser.loc["default"], vhost.filep)
- vhost.enabled = True
- return
+ if not self.parser.parsed_in_original(vhost.filep):
+ # Add direct include to root conf
+ logger.info("Enabling site %s by adding Include to root configuration",
+ vhost.filep)
+ self.save_notes += "Enabled site %s\n" % vhost.filep
+ self.parser.add_include(self.parser.loc["default"], vhost.filep)
+ vhost.enabled = True
+ return
- enabled_path = ("%s/sites-enabled/%s" %
- (self.parser.root, os.path.basename(vhost.filep)))
- self.reverter.register_file_creation(False, enabled_path)
- try:
- os.symlink(vhost.filep, enabled_path)
- except OSError as err:
- if os.path.islink(enabled_path) and os.path.realpath(
- enabled_path) == vhost.filep:
- # Already in shape
- vhost.enabled = True
- return
- else:
- logger.warning(
- "Could not symlink %s to %s, got error: %s", enabled_path,
- vhost.filep, err.strerror)
- errstring = ("Encountered error while trying to enable a " +
- "newly created VirtualHost located at {0} by " +
- "linking to it from {1}")
- raise errors.NotSupportedError(errstring.format(vhost.filep,
- enabled_path))
- vhost.enabled = True
- logger.info("Enabling available site: %s", vhost.filep)
- self.save_notes += "Enabled site %s\n" % vhost.filep
-
- def enable_mod(self, mod_name, temp=False):
+ def enable_mod(self, mod_name, temp=False): # pylint: disable=unused-argument
"""Enables module in Apache.
Both enables and reloads Apache so module is active.
@@ -1764,64 +1769,18 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
:param str mod_name: Name of the module to enable. (e.g. 'ssl')
:param bool temp: Whether or not this is a temporary action.
- :raises .errors.NotSupportedError: If the filesystem layout is not
- supported.
- :raises .errors.MisconfigurationError: If a2enmod or a2dismod cannot be
- run.
+ .. note:: The distribution specific override replaces functionality
+ of this method where available.
+
+ :raises .errors.MisconfigurationError: We cannot enable modules in
+ generic fashion.
"""
- # Support Debian specific setup
- avail_path = os.path.join(self.parser.root, "mods-available")
- enabled_path = os.path.join(self.parser.root, "mods-enabled")
- if not os.path.isdir(avail_path) or not os.path.isdir(enabled_path):
- raise errors.NotSupportedError(
- "Unsupported directory layout. You may try to enable mod %s "
- "and try again." % mod_name)
-
- deps = _get_mod_deps(mod_name)
-
- # Enable all dependencies
- for dep in deps:
- if (dep + "_module") not in self.parser.modules:
- self._enable_mod_debian(dep, temp)
- self._add_parser_mod(dep)
-
- note = "Enabled dependency of %s module - %s" % (mod_name, dep)
- if not temp:
- self.save_notes += note + os.linesep
- logger.debug(note)
-
- # Enable actual module
- self._enable_mod_debian(mod_name, temp)
- self._add_parser_mod(mod_name)
-
- if not temp:
- self.save_notes += "Enabled %s module in Apache\n" % mod_name
- logger.info("Enabled Apache %s module", mod_name)
-
- # Modules can enable additional config files. Variables may be defined
- # within these new configuration sections.
- # Reload is not necessary as DUMP_RUN_CFG uses latest config.
- self.parser.update_runtime_variables()
-
- def _add_parser_mod(self, mod_name):
- """Shortcut for updating parser modules."""
- self.parser.modules.add(mod_name + "_module")
- self.parser.modules.add("mod_" + mod_name + ".c")
-
- def _enable_mod_debian(self, mod_name, temp):
- """Assumes mods-available, mods-enabled layout."""
- # Generate reversal command.
- # Try to be safe here... check that we can probably reverse before
- # applying enmod command
- if not util.exe_exists(self.conf("dismod")):
- raise errors.MisconfigurationError(
- "Unable to find a2dismod, please make sure a2enmod and "
- "a2dismod are configured correctly for certbot.")
-
- self.reverter.register_undo_command(
- temp, [self.conf("dismod"), mod_name])
- util.run_script([self.conf("enmod"), mod_name])
+ mod_message = ("Apache needs to have module \"{0}\" active for the " +
+ "requested installation options. Unfortunately Certbot is unable " +
+ "to install or enable it for you. Please install the module, and " +
+ "run Certbot again.")
+ raise errors.MisconfigurationError(mod_message.format(mod_name))
def restart(self):
"""Runs a config test and reloads the Apache server.
@@ -1840,7 +1799,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
"""
try:
- util.run_script(constants.os_constant("restart_cmd"))
+ util.run_script(self.constant("restart_cmd"))
except errors.SubprocessError as err:
raise errors.MisconfigurationError(str(err))
@@ -1851,7 +1810,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
"""
try:
- util.run_script(constants.os_constant("conftest_cmd"))
+ util.run_script(self.constant("conftest_cmd"))
except errors.SubprocessError as err:
raise errors.MisconfigurationError(str(err))
@@ -1867,11 +1826,11 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
"""
try:
- stdout, _ = util.run_script(constants.os_constant("version_cmd"))
+ stdout, _ = util.run_script(self.constant("version_cmd"))
except errors.SubprocessError:
raise errors.PluginError(
"Unable to run %s -v" %
- constants.os_constant("version_cmd"))
+ self.constant("version_cmd"))
regex = re.compile(r"Apache/([0-9\.]*)", re.IGNORECASE)
matches = regex.findall(stdout)
@@ -1943,86 +1902,15 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
if not self._chall_out:
self.revert_challenge_config()
self.restart()
- self.parser.init_modules()
+ self.parser.reset_modules()
+
+ def install_ssl_options_conf(self, options_ssl, options_ssl_digest):
+ """Copy Certbot's SSL options file into the system's config dir if required."""
+
+ # XXX if we ever try to enforce a local privilege boundary (eg, running
+ # certbot for unprivileged users via setuid), this function will need
+ # to be modified.
+ return common.install_version_controlled_file(options_ssl, options_ssl_digest,
+ self.constant("MOD_SSL_CONF_SRC"), constants.ALL_SSL_OPTIONS_HASHES)
-def _get_mod_deps(mod_name):
- """Get known module dependencies.
-
- .. note:: This does not need to be accurate in order for the client to
- run. This simply keeps things clean if the user decides to revert
- changes.
- .. warning:: If all deps are not included, it may cause incorrect parsing
- behavior, due to enable_mod's shortcut for updating the parser's
- currently defined modules (`.ApacheConfigurator._add_parser_mod`)
- This would only present a major problem in extremely atypical
- configs that use ifmod for the missing deps.
-
- """
- deps = {
- "ssl": ["setenvif", "mime"]
- }
- return deps.get(mod_name, [])
-
-
-def get_file_path(vhost_path):
- """Get file path from augeas_vhost_path.
-
- Takes in Augeas path and returns the file name
-
- :param str vhost_path: Augeas virtual host path
-
- :returns: filename of vhost
- :rtype: str
-
- """
- if not vhost_path or not vhost_path.startswith("/files/"):
- return None
-
- return _split_aug_path(vhost_path)[0]
-
-
-def get_internal_aug_path(vhost_path):
- """Get the Augeas path for a vhost with the file path removed.
-
- :param str vhost_path: Augeas virtual host path
-
- :returns: Augeas path to vhost relative to the containing file
- :rtype: str
-
- """
- return _split_aug_path(vhost_path)[1]
-
-
-def _split_aug_path(vhost_path):
- """Splits an Augeas path into a file path and an internal path.
-
- After removing "/files", this function splits vhost_path into the
- file path and the remaining Augeas path.
-
- :param str vhost_path: Augeas virtual host path
-
- :returns: file path and internal Augeas path
- :rtype: `tuple` of `str`
-
- """
- # Strip off /files
- file_path = vhost_path[6:]
- internal_path = []
-
- # Remove components from the end of file_path until it becomes valid
- while not os.path.exists(file_path):
- file_path, _, internal_path_part = file_path.rpartition("/")
- internal_path.append(internal_path_part)
-
- return file_path, "/".join(reversed(internal_path))
-
-
-def install_ssl_options_conf(options_ssl, options_ssl_digest):
- """Copy Certbot's SSL options file into the system's config dir if required."""
-
- # XXX if we ever try to enforce a local privilege boundary (eg, running
- # certbot for unprivileged users via setuid), this function will need
- # to be modified.
- return common.install_version_controlled_file(options_ssl, options_ssl_digest,
- constants.os_constant("MOD_SSL_CONF_SRC"), constants.ALL_SSL_OPTIONS_HASHES)
diff --git a/certbot-apache/certbot_apache/constants.py b/certbot-apache/certbot_apache/constants.py
index 0c5f7263a..a13ca04a6 100644
--- a/certbot-apache/certbot_apache/constants.py
+++ b/certbot-apache/certbot_apache/constants.py
@@ -1,151 +1,6 @@
"""Apache plugin constants."""
import pkg_resources
-from certbot import util
-CLI_DEFAULTS_DEFAULT = dict(
- server_root="/etc/apache2",
- vhost_root="/etc/apache2/sites-available",
- vhost_files="*",
- logs_root="/var/log/apache2",
- version_cmd=['apache2ctl', '-v'],
- define_cmd=['apache2ctl', '-t', '-D', 'DUMP_RUN_CFG'],
- restart_cmd=['apache2ctl', 'graceful'],
- conftest_cmd=['apache2ctl', 'configtest'],
- enmod=None,
- dismod=None,
- le_vhost_ext="-le-ssl.conf",
- handle_mods=False,
- handle_sites=False,
- challenge_location="/etc/apache2",
- MOD_SSL_CONF_SRC=pkg_resources.resource_filename(
- "certbot_apache", "options-ssl-apache.conf")
-)
-CLI_DEFAULTS_DEBIAN = dict(
- server_root="/etc/apache2",
- vhost_root="/etc/apache2/sites-available",
- vhost_files="*",
- logs_root="/var/log/apache2",
- version_cmd=['apache2ctl', '-v'],
- define_cmd=['apache2ctl', '-t', '-D', 'DUMP_RUN_CFG'],
- restart_cmd=['apache2ctl', 'graceful'],
- conftest_cmd=['apache2ctl', 'configtest'],
- enmod="a2enmod",
- dismod="a2dismod",
- le_vhost_ext="-le-ssl.conf",
- handle_mods=True,
- handle_sites=True,
- challenge_location="/etc/apache2",
- MOD_SSL_CONF_SRC=pkg_resources.resource_filename(
- "certbot_apache", "options-ssl-apache.conf")
-)
-CLI_DEFAULTS_CENTOS = dict(
- server_root="/etc/httpd",
- vhost_root="/etc/httpd/conf.d",
- vhost_files="*.conf",
- logs_root="/var/log/httpd",
- version_cmd=['apachectl', '-v'],
- define_cmd=['apachectl', '-t', '-D', 'DUMP_RUN_CFG'],
- restart_cmd=['apachectl', 'graceful'],
- conftest_cmd=['apachectl', 'configtest'],
- enmod=None,
- dismod=None,
- le_vhost_ext="-le-ssl.conf",
- handle_mods=False,
- handle_sites=False,
- challenge_location="/etc/httpd/conf.d",
- MOD_SSL_CONF_SRC=pkg_resources.resource_filename(
- "certbot_apache", "centos-options-ssl-apache.conf")
-)
-CLI_DEFAULTS_GENTOO = dict(
- server_root="/etc/apache2",
- vhost_root="/etc/apache2/vhosts.d",
- vhost_files="*.conf",
- logs_root="/var/log/apache2",
- version_cmd=['/usr/sbin/apache2', '-v'],
- define_cmd=['apache2ctl', 'virtualhosts'],
- restart_cmd=['apache2ctl', 'graceful'],
- conftest_cmd=['apache2ctl', 'configtest'],
- enmod=None,
- dismod=None,
- le_vhost_ext="-le-ssl.conf",
- handle_mods=False,
- handle_sites=False,
- challenge_location="/etc/apache2/vhosts.d",
- MOD_SSL_CONF_SRC=pkg_resources.resource_filename(
- "certbot_apache", "options-ssl-apache.conf")
-)
-CLI_DEFAULTS_DARWIN = dict(
- server_root="/etc/apache2",
- vhost_root="/etc/apache2/other",
- vhost_files="*.conf",
- logs_root="/var/log/apache2",
- version_cmd=['/usr/sbin/httpd', '-v'],
- define_cmd=['/usr/sbin/httpd', '-t', '-D', 'DUMP_RUN_CFG'],
- restart_cmd=['apachectl', 'graceful'],
- conftest_cmd=['apachectl', 'configtest'],
- enmod=None,
- dismod=None,
- le_vhost_ext="-le-ssl.conf",
- handle_mods=False,
- handle_sites=False,
- challenge_location="/etc/apache2/other",
- MOD_SSL_CONF_SRC=pkg_resources.resource_filename(
- "certbot_apache", "options-ssl-apache.conf")
-)
-CLI_DEFAULTS_SUSE = dict(
- server_root="/etc/apache2",
- vhost_root="/etc/apache2/vhosts.d",
- vhost_files="*.conf",
- logs_root="/var/log/apache2",
- version_cmd=['apache2ctl', '-v'],
- define_cmd=['apache2ctl', '-t', '-D', 'DUMP_RUN_CFG'],
- restart_cmd=['apache2ctl', 'graceful'],
- conftest_cmd=['apache2ctl', 'configtest'],
- enmod="a2enmod",
- dismod="a2dismod",
- le_vhost_ext="-le-ssl.conf",
- handle_mods=False,
- handle_sites=False,
- challenge_location="/etc/apache2/vhosts.d",
- MOD_SSL_CONF_SRC=pkg_resources.resource_filename(
- "certbot_apache", "options-ssl-apache.conf")
-)
-CLI_DEFAULTS_ARCH = dict(
- server_root="/etc/httpd",
- vhost_root="/etc/httpd/conf",
- vhost_files="*.conf",
- logs_root="/var/log/httpd",
- version_cmd=['apachectl', '-v'],
- define_cmd=['apachectl', '-t', '-D', 'DUMP_RUN_CFG'],
- restart_cmd=['apachectl', 'graceful'],
- conftest_cmd=['apachectl', 'configtest'],
- enmod=None,
- dismod=None,
- le_vhost_ext="-le-ssl.conf",
- handle_mods=False,
- handle_sites=False,
- challenge_location="/etc/httpd/conf",
- MOD_SSL_CONF_SRC=pkg_resources.resource_filename(
- "certbot_apache", "options-ssl-apache.conf")
-)
-CLI_DEFAULTS = {
- "default": CLI_DEFAULTS_DEFAULT,
- "debian": CLI_DEFAULTS_DEBIAN,
- "ubuntu": CLI_DEFAULTS_DEBIAN,
- "centos": CLI_DEFAULTS_CENTOS,
- "centos linux": CLI_DEFAULTS_CENTOS,
- "fedora": CLI_DEFAULTS_CENTOS,
- "red hat enterprise linux server": CLI_DEFAULTS_CENTOS,
- "rhel": CLI_DEFAULTS_CENTOS,
- "amazon": CLI_DEFAULTS_CENTOS,
- "gentoo": CLI_DEFAULTS_GENTOO,
- "gentoo base system": CLI_DEFAULTS_GENTOO,
- "darwin": CLI_DEFAULTS_DARWIN,
- "opensuse": CLI_DEFAULTS_SUSE,
- "suse": CLI_DEFAULTS_SUSE,
- "arch": CLI_DEFAULTS_ARCH,
-}
-"""CLI defaults."""
MOD_SSL_CONF_DEST = "options-ssl-apache.conf"
"""Name of the mod_ssl config file as saved in `IConfig.config_dir`."""
@@ -191,39 +46,3 @@ UIR_ARGS = ["always", "set", "Content-Security-Policy",
HEADER_ARGS = {"Strict-Transport-Security": HSTS_ARGS,
"Upgrade-Insecure-Requests": UIR_ARGS}
-
-
-def os_constant(key):
- """
- Get a constant value for operating system
-
- :param key: name of cli constant
- :return: value of constant for active os
- """
-
- os_info = util.get_os_info()
- try:
- constants = CLI_DEFAULTS[os_info[0].lower()]
- except KeyError:
- constants = os_like_constants()
- if not constants:
- constants = CLI_DEFAULTS["default"]
- return constants[key]
-
-
-def os_like_constants():
- """
- Try to get constants for distribution with
- similar layout and configuration, indicated by
- /etc/os-release variable "LIKE"
-
- :returns: Constants dictionary
- :rtype: `dict`
- """
-
- os_like = util.get_systemd_os_like()
- if os_like:
- for os_name in os_like:
- if os_name in CLI_DEFAULTS.keys():
- return CLI_DEFAULTS[os_name]
- return {}
diff --git a/certbot-apache/certbot_apache/entrypoint.py b/certbot-apache/certbot_apache/entrypoint.py
new file mode 100644
index 000000000..4267398d5
--- /dev/null
+++ b/certbot-apache/certbot_apache/entrypoint.py
@@ -0,0 +1,47 @@
+""" Entry point for Apache Plugin """
+from certbot import util
+
+from certbot_apache import configurator
+from certbot_apache import override_arch
+from certbot_apache import override_darwin
+from certbot_apache import override_debian
+from certbot_apache import override_centos
+from certbot_apache import override_gentoo
+from certbot_apache import override_suse
+
+OVERRIDE_CLASSES = {
+ "arch": override_arch.ArchConfigurator,
+ "darwin": override_darwin.DarwinConfigurator,
+ "debian": override_debian.DebianConfigurator,
+ "ubuntu": override_debian.DebianConfigurator,
+ "centos": override_centos.CentOSConfigurator,
+ "centos linux": override_centos.CentOSConfigurator,
+ "fedora": override_centos.CentOSConfigurator,
+ "red hat enterprise linux server": override_centos.CentOSConfigurator,
+ "rhel": override_centos.CentOSConfigurator,
+ "amazon": override_centos.CentOSConfigurator,
+ "gentoo": override_gentoo.GentooConfigurator,
+ "gentoo base system": override_gentoo.GentooConfigurator,
+ "opensuse": override_suse.OpenSUSEConfigurator,
+ "suse": override_suse.OpenSUSEConfigurator,
+}
+
+def get_configurator():
+ """ Get correct configurator class based on the OS fingerprint """
+ os_info = util.get_os_info()
+ override_class = None
+ try:
+ override_class = OVERRIDE_CLASSES[os_info[0].lower()]
+ except KeyError:
+ # OS not found in the list
+ os_like = util.get_systemd_os_like()
+ if os_like:
+ for os_name in os_like:
+ if os_name in OVERRIDE_CLASSES.keys():
+ override_class = OVERRIDE_CLASSES[os_name]
+ if not override_class:
+ # No override class found, return the generic configurator
+ override_class = configurator.ApacheConfigurator
+ return override_class
+
+ENTRYPOINT = get_configurator()
diff --git a/certbot-apache/certbot_apache/override_arch.py b/certbot-apache/certbot_apache/override_arch.py
new file mode 100644
index 000000000..ea5155a3c
--- /dev/null
+++ b/certbot-apache/certbot_apache/override_arch.py
@@ -0,0 +1,31 @@
+""" Distribution specific override class for Arch Linux """
+import pkg_resources
+
+import zope.interface
+
+from certbot import interfaces
+
+from certbot_apache import configurator
+
+@zope.interface.provider(interfaces.IPluginFactory)
+class ArchConfigurator(configurator.ApacheConfigurator):
+ """Arch Linux specific ApacheConfigurator override class"""
+
+ OS_DEFAULTS = dict(
+ server_root="/etc/httpd",
+ vhost_root="/etc/httpd/conf",
+ vhost_files="*.conf",
+ logs_root="/var/log/httpd",
+ version_cmd=['apachectl', '-v'],
+ apache_cmd="apachectl",
+ restart_cmd=['apachectl', 'graceful'],
+ conftest_cmd=['apachectl', 'configtest'],
+ enmod=None,
+ dismod=None,
+ le_vhost_ext="-le-ssl.conf",
+ handle_mods=False,
+ handle_sites=False,
+ challenge_location="/etc/httpd/conf",
+ MOD_SSL_CONF_SRC=pkg_resources.resource_filename(
+ "certbot_apache", "options-ssl-apache.conf")
+ )
diff --git a/certbot-apache/certbot_apache/override_centos.py b/certbot-apache/certbot_apache/override_centos.py
new file mode 100644
index 000000000..db6cd6fba
--- /dev/null
+++ b/certbot-apache/certbot_apache/override_centos.py
@@ -0,0 +1,59 @@
+""" Distribution specific override class for CentOS family (RHEL, Fedora) """
+import pkg_resources
+
+import zope.interface
+
+from certbot import interfaces
+
+from certbot_apache import apache_util
+from certbot_apache import configurator
+from certbot_apache import parser
+
+@zope.interface.provider(interfaces.IPluginFactory)
+class CentOSConfigurator(configurator.ApacheConfigurator):
+ """CentOS specific ApacheConfigurator override class"""
+
+ OS_DEFAULTS = dict(
+ server_root="/etc/httpd",
+ vhost_root="/etc/httpd/conf.d",
+ vhost_files="*.conf",
+ logs_root="/var/log/httpd",
+ version_cmd=['apachectl', '-v'],
+ apache_cmd="apachectl",
+ restart_cmd=['apachectl', 'graceful'],
+ conftest_cmd=['apachectl', 'configtest'],
+ enmod=None,
+ dismod=None,
+ le_vhost_ext="-le-ssl.conf",
+ handle_mods=False,
+ handle_sites=False,
+ challenge_location="/etc/httpd/conf.d",
+ MOD_SSL_CONF_SRC=pkg_resources.resource_filename(
+ "certbot_apache", "centos-options-ssl-apache.conf")
+ )
+
+ def get_parser(self):
+ """Initializes the ApacheParser"""
+ return CentOSParser(
+ self.aug, self.conf("server-root"), self.conf("vhost-root"),
+ self.version, configurator=self)
+
+
+class CentOSParser(parser.ApacheParser):
+ """CentOS specific ApacheParser override class"""
+ def __init__(self, *args, **kwargs):
+ # CentOS specific configuration file for Apache
+ self.sysconfig_filep = "/etc/sysconfig/httpd"
+ super(CentOSParser, self).__init__(*args, **kwargs)
+
+ def update_runtime_variables(self, *args, **kwargs):
+ """ Override for update_runtime_variables for custom parsing """
+ # Opportunistic, works if SELinux not enforced
+ super(CentOSParser, self).update_runtime_variables(*args, **kwargs)
+ self.parse_sysconfig_var()
+
+ def parse_sysconfig_var(self):
+ """ Parses Apache CLI options from CentOS configuration file """
+ defines = apache_util.parse_define_file(self.sysconfig_filep, "OPTIONS")
+ for k in defines.keys():
+ self.variables[k] = defines[k]
diff --git a/certbot-apache/certbot_apache/override_darwin.py b/certbot-apache/certbot_apache/override_darwin.py
new file mode 100644
index 000000000..53741d504
--- /dev/null
+++ b/certbot-apache/certbot_apache/override_darwin.py
@@ -0,0 +1,31 @@
+""" Distribution specific override class for macOS """
+import pkg_resources
+
+import zope.interface
+
+from certbot import interfaces
+
+from certbot_apache import configurator
+
+@zope.interface.provider(interfaces.IPluginFactory)
+class DarwinConfigurator(configurator.ApacheConfigurator):
+ """macOS specific ApacheConfigurator override class"""
+
+ OS_DEFAULTS = dict(
+ server_root="/etc/apache2",
+ vhost_root="/etc/apache2/other",
+ vhost_files="*.conf",
+ logs_root="/var/log/apache2",
+ version_cmd=['/usr/sbin/httpd', '-v'],
+ apache_cmd="/usr/sbin/httpd",
+ restart_cmd=['apachectl', 'graceful'],
+ conftest_cmd=['apachectl', 'configtest'],
+ enmod=None,
+ dismod=None,
+ le_vhost_ext="-le-ssl.conf",
+ handle_mods=False,
+ handle_sites=False,
+ challenge_location="/etc/apache2/other",
+ MOD_SSL_CONF_SRC=pkg_resources.resource_filename(
+ "certbot_apache", "options-ssl-apache.conf")
+ )
diff --git a/certbot-apache/certbot_apache/override_debian.py b/certbot-apache/certbot_apache/override_debian.py
new file mode 100644
index 000000000..6e2e34ba9
--- /dev/null
+++ b/certbot-apache/certbot_apache/override_debian.py
@@ -0,0 +1,144 @@
+""" Distribution specific override class for Debian family (Ubuntu/Debian) """
+import logging
+import os
+import pkg_resources
+
+import zope.interface
+
+from certbot import errors
+from certbot import interfaces
+from certbot import util
+
+from certbot_apache import apache_util
+from certbot_apache import configurator
+
+logger = logging.getLogger(__name__)
+
+@zope.interface.provider(interfaces.IPluginFactory)
+class DebianConfigurator(configurator.ApacheConfigurator):
+ """Debian specific ApacheConfigurator override class"""
+
+ OS_DEFAULTS = dict(
+ server_root="/etc/apache2",
+ vhost_root="/etc/apache2/sites-available",
+ vhost_files="*",
+ logs_root="/var/log/apache2",
+ version_cmd=['apache2ctl', '-v'],
+ apache_cmd="apache2ctl",
+ restart_cmd=['apache2ctl', 'graceful'],
+ conftest_cmd=['apache2ctl', 'configtest'],
+ enmod="a2enmod",
+ dismod="a2dismod",
+ le_vhost_ext="-le-ssl.conf",
+ handle_mods=True,
+ handle_sites=True,
+ challenge_location="/etc/apache2",
+ MOD_SSL_CONF_SRC=pkg_resources.resource_filename(
+ "certbot_apache", "options-ssl-apache.conf")
+ )
+
+ def enable_site(self, vhost):
+ """Enables an available site, Apache reload required.
+
+ .. note:: Does not make sure that the site correctly works or that all
+ modules are enabled appropriately.
+
+ :param vhost: vhost to enable
+ :type vhost: :class:`~certbot_apache.obj.VirtualHost`
+
+ :raises .errors.NotSupportedError: If filesystem layout is not
+ supported.
+
+ """
+ if vhost.enabled:
+ return
+
+ enabled_path = ("%s/sites-enabled/%s" %
+ (self.parser.root,
+ os.path.basename(vhost.filep)))
+ if not os.path.isdir(os.path.dirname(enabled_path)):
+ # For some reason, sites-enabled / sites-available do not exist
+ # Call the parent method
+ return super(DebianConfigurator, self).enable_site(vhost)
+ self.reverter.register_file_creation(False, enabled_path)
+ try:
+ os.symlink(vhost.filep, enabled_path)
+ except OSError as err:
+ if os.path.islink(enabled_path) and os.path.realpath(
+ enabled_path) == vhost.filep:
+ # Already in shape
+ vhost.enabled = True
+ return
+ else:
+ logger.warning(
+ "Could not symlink %s to %s, got error: %s", enabled_path,
+ vhost.filep, err.strerror)
+ errstring = ("Encountered error while trying to enable a " +
+ "newly created VirtualHost located at {0} by " +
+ "linking to it from {1}")
+ raise errors.NotSupportedError(errstring.format(vhost.filep,
+ enabled_path))
+ vhost.enabled = True
+ logger.info("Enabling available site: %s", vhost.filep)
+ self.save_notes += "Enabled site %s\n" % vhost.filep
+
+ def enable_mod(self, mod_name, temp=False):
+ # pylint: disable=unused-argument
+ """Enables module in Apache.
+
+ Both enables and reloads Apache so module is active.
+
+ :param str mod_name: Name of the module to enable. (e.g. 'ssl')
+ :param bool temp: Whether or not this is a temporary action.
+
+ :raises .errors.NotSupportedError: If the filesystem layout is not
+ supported.
+ :raises .errors.MisconfigurationError: If a2enmod or a2dismod cannot be
+ run.
+
+ """
+ avail_path = os.path.join(self.parser.root, "mods-available")
+ enabled_path = os.path.join(self.parser.root, "mods-enabled")
+ if not os.path.isdir(avail_path) or not os.path.isdir(enabled_path):
+ raise errors.NotSupportedError(
+ "Unsupported directory layout. You may try to enable mod %s "
+ "and try again." % mod_name)
+
+ deps = apache_util.get_mod_deps(mod_name)
+
+ # Enable all dependencies
+ for dep in deps:
+ if (dep + "_module") not in self.parser.modules:
+ self._enable_mod_debian(dep, temp)
+ self.parser.add_mod(dep)
+ note = "Enabled dependency of %s module - %s" % (mod_name, dep)
+ if not temp:
+ self.save_notes += note + os.linesep
+ logger.debug(note)
+
+ # Enable actual module
+ self._enable_mod_debian(mod_name, temp)
+ self.parser.add_mod(mod_name)
+
+ if not temp:
+ self.save_notes += "Enabled %s module in Apache\n" % mod_name
+ logger.info("Enabled Apache %s module", mod_name)
+
+ # Modules can enable additional config files. Variables may be defined
+ # within these new configuration sections.
+ # Reload is not necessary as DUMP_RUN_CFG uses latest config.
+ self.parser.update_runtime_variables()
+
+ def _enable_mod_debian(self, mod_name, temp):
+ """Assumes mods-available, mods-enabled layout."""
+ # Generate reversal command.
+ # Try to be safe here... check that we can probably reverse before
+ # applying enmod command
+ if not util.exe_exists(self.conf("dismod")):
+ raise errors.MisconfigurationError(
+ "Unable to find a2dismod, please make sure a2enmod and "
+ "a2dismod are configured correctly for certbot.")
+
+ self.reverter.register_undo_command(
+ temp, [self.conf("dismod"), mod_name])
+ util.run_script([self.conf("enmod"), mod_name])
diff --git a/certbot-apache/certbot_apache/override_gentoo.py b/certbot-apache/certbot_apache/override_gentoo.py
new file mode 100644
index 000000000..d4d4e96b9
--- /dev/null
+++ b/certbot-apache/certbot_apache/override_gentoo.py
@@ -0,0 +1,58 @@
+""" Distribution specific override class for Gentoo Linux """
+import pkg_resources
+
+import zope.interface
+
+from certbot import interfaces
+
+from certbot_apache import apache_util
+from certbot_apache import configurator
+from certbot_apache import parser
+
+@zope.interface.provider(interfaces.IPluginFactory)
+class GentooConfigurator(configurator.ApacheConfigurator):
+ """Gentoo specific ApacheConfigurator override class"""
+
+ OS_DEFAULTS = dict(
+ server_root="/etc/apache2",
+ vhost_root="/etc/apache2/vhosts.d",
+ vhost_files="*.conf",
+ logs_root="/var/log/apache2",
+ version_cmd=['/usr/sbin/apache2', '-v'],
+ apache_cmd="apache2ctl",
+ restart_cmd=['apache2ctl', 'graceful'],
+ conftest_cmd=['apache2ctl', 'configtest'],
+ enmod=None,
+ dismod=None,
+ le_vhost_ext="-le-ssl.conf",
+ handle_mods=False,
+ handle_sites=False,
+ challenge_location="/etc/apache2/vhosts.d",
+ MOD_SSL_CONF_SRC=pkg_resources.resource_filename(
+ "certbot_apache", "options-ssl-apache.conf")
+ )
+
+ def get_parser(self):
+ """Initializes the ApacheParser"""
+ return GentooParser(
+ self.aug, self.conf("server-root"), self.conf("vhost-root"),
+ self.version, configurator=self)
+
+
+class GentooParser(parser.ApacheParser):
+ """Gentoo specific ApacheParser override class"""
+ def __init__(self, *args, **kwargs):
+ # Gentoo specific configuration file for Apache2
+ self.apacheconfig_filep = "/etc/conf.d/apache2"
+ super(GentooParser, self).__init__(*args, **kwargs)
+
+ def update_runtime_variables(self):
+ """ Override for update_runtime_variables for custom parsing """
+ self.parse_sysconfig_var()
+
+ def parse_sysconfig_var(self):
+ """ Parses Apache CLI options from Gentoo configuration file """
+ defines = apache_util.parse_define_file(self.apacheconfig_filep,
+ "APACHE2_OPTS")
+ for k in defines.keys():
+ self.variables[k] = defines[k]
diff --git a/certbot-apache/certbot_apache/override_suse.py b/certbot-apache/certbot_apache/override_suse.py
new file mode 100644
index 000000000..a67054b5b
--- /dev/null
+++ b/certbot-apache/certbot_apache/override_suse.py
@@ -0,0 +1,31 @@
+""" Distribution specific override class for OpenSUSE """
+import pkg_resources
+
+import zope.interface
+
+from certbot import interfaces
+
+from certbot_apache import configurator
+
+@zope.interface.provider(interfaces.IPluginFactory)
+class OpenSUSEConfigurator(configurator.ApacheConfigurator):
+ """OpenSUSE specific ApacheConfigurator override class"""
+
+ OS_DEFAULTS = dict(
+ server_root="/etc/apache2",
+ vhost_root="/etc/apache2/vhosts.d",
+ vhost_files="*.conf",
+ logs_root="/var/log/apache2",
+ version_cmd=['apache2ctl', '-v'],
+ apache_cmd="apache2ctl",
+ restart_cmd=['apache2ctl', 'graceful'],
+ conftest_cmd=['apache2ctl', 'configtest'],
+ enmod="a2enmod",
+ dismod="a2dismod",
+ le_vhost_ext="-le-ssl.conf",
+ handle_mods=False,
+ handle_sites=False,
+ challenge_location="/etc/apache2/vhosts.d",
+ MOD_SSL_CONF_SRC=pkg_resources.resource_filename(
+ "certbot_apache", "options-ssl-apache.conf")
+ )
diff --git a/certbot-apache/certbot_apache/parser.py b/certbot-apache/certbot_apache/parser.py
index b15608d61..7715d2c35 100644
--- a/certbot-apache/certbot_apache/parser.py
+++ b/certbot-apache/certbot_apache/parser.py
@@ -11,8 +11,6 @@ import six
from certbot import errors
-from certbot_apache import constants
-
logger = logging.getLogger(__name__)
@@ -40,14 +38,9 @@ class ApacheParser(object):
# issues with aug.load() after adding new files / defines to parse tree
self.configurator = configurator
- # This uses the binary, so it can be done first.
- # https://httpd.apache.org/docs/2.4/mod/core.html#define
- # https://httpd.apache.org/docs/2.4/mod/core.html#ifdefine
- # This only handles invocation parameters and Define directives!
+ self.modules = set()
self.parser_paths = {}
self.variables = {}
- if version >= (2, 4):
- self.update_runtime_variables()
self.aug = aug
# Find configuration root and make sure augeas can parse it.
@@ -55,24 +48,26 @@ class ApacheParser(object):
self.loc = {"root": self._find_config_root()}
self.parse_file(self.loc["root"])
+ if version >= (2, 4):
+ # Look up variables from httpd and add to DOM if not already parsed
+ self.update_runtime_variables()
+
# This problem has been fixed in Augeas 1.0
self.standardize_excl()
- # Temporarily set modules to be empty, so that find_dirs can work
- # https://httpd.apache.org/docs/2.4/mod/core.html#ifmodule
- # This needs to come before locations are set.
- self.modules = set()
- self.init_modules()
+ # Parse LoadModule directives from configuration files
+ self.parse_modules()
# Set up rest of locations
self.loc.update(self._set_locations())
+ # list of the active include paths, before modifications
self.existing_paths = copy.deepcopy(self.parser_paths)
# Must also attempt to parse additional virtual host root
if vhostroot:
self.parse_file(os.path.abspath(vhostroot) + "/" +
- constants.os_constant("vhost_files"))
+ self.configurator.constant("vhost_files"))
# check to see if there were unparsed define statements
if version < (2, 4):
@@ -103,50 +98,61 @@ class ApacheParser(object):
# Create a new path
self.existing_paths[new_dir] = [new_file]
- def init_modules(self):
+ def add_mod(self, mod_name):
+ """Shortcut for updating parser modules."""
+ if mod_name + "_module" not in self.modules:
+ self.modules.add(mod_name + "_module")
+ if "mod_" + mod_name + ".c" not in self.modules:
+ self.modules.add("mod_" + mod_name + ".c")
+
+ def reset_modules(self):
+ """Reset the loaded modules list. This is called from cleanup to clear
+ temporarily loaded modules."""
+ self.modules = set()
+ self.update_modules()
+ self.parse_modules()
+
+ def parse_modules(self):
"""Iterates on the configuration until no new modules are loaded.
..todo:: This should be attempted to be done with a binary to avoid
the iteration issue. Else... parse and enable mods at same time.
"""
- # Since modules are being initiated... clear existing set.
- self.modules = set()
+ mods = set()
matches = self.find_dir("LoadModule")
-
iterator = iter(matches)
# Make sure prev_size != cur_size for do: while: iteration
prev_size = -1
- while len(self.modules) != prev_size:
- prev_size = len(self.modules)
+ while len(mods) != prev_size:
+ prev_size = len(mods)
for match_name, match_filename in six.moves.zip(
iterator, iterator):
mod_name = self.get_arg(match_name)
mod_filename = self.get_arg(match_filename)
if mod_name and mod_filename:
- self.modules.add(mod_name)
- self.modules.add(os.path.basename(mod_filename)[:-2] + "c")
+ mods.add(mod_name)
+ mods.add(os.path.basename(mod_filename)[:-2] + "c")
else:
logger.debug("Could not read LoadModule directive from " +
"Augeas path: {0}".format(match_name[6:]))
+ self.modules.update(mods)
def update_runtime_variables(self):
- """"
+ """Update Includes, Defines and Includes from httpd config dump data"""
+ self.update_defines()
+ self.update_includes()
+ self.update_modules()
- .. note:: Compile time variables (apache2ctl -V) are not used within
- the dynamic configuration files. These should not be parsed or
- interpreted.
-
- .. todo:: Create separate compile time variables...
- simply for arg_get()
-
- """
- stdout = self._get_runtime_cfg()
+ def update_defines(self):
+ """Get Defines from httpd process"""
variables = dict()
- matches = re.compile(r"Define: ([^ \n]*)").findall(stdout)
+ define_cmd = [self.configurator.constant("apache_cmd"), "-t", "-D",
+ "DUMP_RUN_CFG"]
+ matches = self.parse_from_subprocess(define_cmd, r"Define: ([^ \n]*)")
try:
matches.remove("DUMP_RUN_CFG")
except ValueError:
@@ -163,15 +169,54 @@ class ApacheParser(object):
self.variables = variables
- def _get_runtime_cfg(self): # pylint: disable=no-self-use
- """Get runtime configuration info.
+ def update_includes(self):
+ """Get includes from httpd process, and add them to DOM if needed"""
- :returns: stdout from DUMP_RUN_CFG
+ # Find_dir iterates over configuration for Include and IncludeOptional
+ # directives to make sure we see the full include tree present in the
+ # configuration files
+ _ = self.find_dir("Include")
+
+ inc_cmd = [self.configurator.constant("apache_cmd"), "-t", "-D",
+ "DUMP_INCLUDES"]
+ matches = self.parse_from_subprocess(inc_cmd, r"\(.*\) (.*)")
+ if matches:
+ for i in matches:
+ if not self.parsed_in_current(i):
+ self.parse_file(i)
+
+ def update_modules(self):
+ """Get loaded modules from httpd process, and add them to DOM"""
+
+ mod_cmd = [self.configurator.constant("apache_cmd"), "-t", "-D",
+ "DUMP_MODULES"]
+ matches = self.parse_from_subprocess(mod_cmd, r"(.*)_module")
+ for mod in matches:
+ self.add_mod(mod.strip())
+
+ def parse_from_subprocess(self, command, regexp):
+ """Get values from stdout of subprocess command
+
+ :param list command: Command to run
+ :param str regexp: Regexp for parsing
+
+ :returns: list parsed from command output
+ :rtype: list
+
+ """
+ stdout = self._get_runtime_cfg(command)
+ return re.compile(regexp).findall(stdout)
+
+ def _get_runtime_cfg(self, command): # pylint: disable=no-self-use
+ """Get runtime configuration info.
+ :param command: Command to run
+
+ :returns: stdout from command
"""
try:
proc = subprocess.Popen(
- constants.os_constant("define_cmd"),
+ command,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
universal_newlines=True)
@@ -180,10 +225,10 @@ class ApacheParser(object):
except (OSError, ValueError):
logger.error(
"Error running command %s for runtime parameters!%s",
- constants.os_constant("define_cmd"), os.linesep)
+ command, os.linesep)
raise errors.MisconfigurationError(
"Error accessing loaded Apache parameters: %s",
- constants.os_constant("define_cmd"))
+ command)
# Small errors that do not impede
if proc.returncode != 0:
logger.warning("Error in checking parameter list: %s", stderr)
diff --git a/certbot-apache/certbot_apache/tests/centos_test.py b/certbot-apache/certbot_apache/tests/centos_test.py
new file mode 100644
index 000000000..7ca47a4d5
--- /dev/null
+++ b/certbot-apache/certbot_apache/tests/centos_test.py
@@ -0,0 +1,123 @@
+"""Test for certbot_apache.configurator for Centos overrides"""
+import os
+import unittest
+
+import mock
+
+from certbot_apache import obj
+from certbot_apache import override_centos
+from certbot_apache.tests import util
+
+def get_vh_truth(temp_dir, config_name):
+ """Return the ground truth for the specified directory."""
+ prefix = os.path.join(
+ temp_dir, config_name, "httpd/conf.d")
+
+ aug_pre = "/files" + prefix
+ vh_truth = [
+ obj.VirtualHost(
+ os.path.join(prefix, "centos.example.com.conf"),
+ os.path.join(aug_pre, "centos.example.com.conf/VirtualHost"),
+ set([obj.Addr.fromstring("*:80")]),
+ False, True, "centos.example.com"),
+ obj.VirtualHost(
+ os.path.join(prefix, "ssl.conf"),
+ os.path.join(aug_pre, "ssl.conf/VirtualHost"),
+ set([obj.Addr.fromstring("_default_:443")]),
+ True, True, None)
+ ]
+ return vh_truth
+
+class MultipleVhostsTestCentOS(util.ApacheTest):
+ """Multiple vhost tests for CentOS / RHEL family of distros"""
+
+ _multiprocess_can_split_ = True
+
+ def setUp(self): # pylint: disable=arguments-differ
+ test_dir = "centos7_apache/apache"
+ config_root = "centos7_apache/apache/httpd"
+ vhost_root = "centos7_apache/apache/httpd/conf.d"
+ super(MultipleVhostsTestCentOS, self).setUp(test_dir=test_dir,
+ config_root=config_root,
+ vhost_root=vhost_root)
+
+ self.config = util.get_apache_configurator(
+ self.config_path, self.vhost_path, self.config_dir, self.work_dir,
+ os_info="centos")
+ self.vh_truth = get_vh_truth(
+ self.temp_dir, "centos7_apache/apache")
+
+ def test_get_parser(self):
+ self.assertTrue(isinstance(self.config.parser,
+ override_centos.CentOSParser))
+
+ @mock.patch("certbot_apache.parser.ApacheParser._get_runtime_cfg")
+ def test_opportunistic_httpd_runtime_parsing(self, mock_get):
+ define_val = (
+ 'Define: TEST1\n'
+ 'Define: TEST2\n'
+ 'Define: DUMP_RUN_CFG\n'
+ )
+ mod_val = (
+ 'Loaded Modules:\n'
+ ' mock_module (static)\n'
+ ' another_module (static)\n'
+ )
+ def mock_get_cfg(command):
+ """Mock httpd process stdout"""
+ if command == ['apachectl', '-t', '-D', 'DUMP_RUN_CFG']:
+ return define_val
+ elif command == ['apachectl', '-t', '-D', 'DUMP_MODULES']:
+ return mod_val
+ return ""
+ mock_get.side_effect = mock_get_cfg
+ self.config.parser.modules = set()
+ self.config.parser.variables = {}
+
+ with mock.patch("certbot.util.get_os_info") as mock_osi:
+ # Make sure we have the have the CentOS httpd constants
+ mock_osi.return_value = ("centos", "7")
+ self.config.parser.update_runtime_variables()
+
+ self.assertEquals(mock_get.call_count, 3)
+ self.assertEquals(len(self.config.parser.modules), 4)
+ self.assertEquals(len(self.config.parser.variables), 2)
+ self.assertTrue("TEST2" in self.config.parser.variables.keys())
+ self.assertTrue("mod_another.c" in self.config.parser.modules)
+
+ def test_get_virtual_hosts(self):
+ """Make sure all vhosts are being properly found."""
+ vhs = self.config.get_virtual_hosts()
+ self.assertEqual(len(vhs), 2)
+ found = 0
+
+ for vhost in vhs:
+ for centos_truth in self.vh_truth:
+ if vhost == centos_truth:
+ found += 1
+ break
+ else:
+ raise Exception("Missed: %s" % vhost) # pragma: no cover
+ self.assertEqual(found, 2)
+
+ @mock.patch("certbot_apache.parser.ApacheParser._get_runtime_cfg")
+ def test_get_sysconfig_vars(self, mock_cfg):
+ """Make sure we read the sysconfig OPTIONS variable correctly"""
+ # Return nothing for the process calls
+ mock_cfg.return_value = ""
+ self.config.parser.sysconfig_filep = os.path.realpath(
+ os.path.join(self.config.parser.root, "../sysconfig/httpd"))
+ self.config.parser.variables = {}
+
+ with mock.patch("certbot.util.get_os_info") as mock_osi:
+ # Make sure we have the have the CentOS httpd constants
+ mock_osi.return_value = ("centos", "7")
+ self.config.parser.update_runtime_variables()
+
+ self.assertTrue("mock_define" in self.config.parser.variables.keys())
+ self.assertTrue("mock_define_too" in self.config.parser.variables.keys())
+ self.assertTrue("mock_value" in self.config.parser.variables.keys())
+ self.assertEqual("TRUE", self.config.parser.variables["mock_value"])
+
+if __name__ == "__main__":
+ unittest.main() # pragma: no cover
diff --git a/certbot-apache/certbot_apache/tests/complex_parsing_test.py b/certbot-apache/certbot_apache/tests/complex_parsing_test.py
index 079d7e95f..a296fb0eb 100644
--- a/certbot-apache/certbot_apache/tests/complex_parsing_test.py
+++ b/certbot-apache/certbot_apache/tests/complex_parsing_test.py
@@ -18,7 +18,7 @@ class ComplexParserTest(util.ParserTest):
self.setup_variables()
# This needs to happen after due to setup_variables not being run
# until after
- self.parser.init_modules() # pylint: disable=protected-access
+ self.parser.parse_modules() # pylint: disable=protected-access
def tearDown(self):
shutil.rmtree(self.temp_dir)
diff --git a/certbot-apache/certbot_apache/tests/configurator_test.py b/certbot-apache/certbot_apache/tests/configurator_test.py
index 90561d6ad..4f85e1e3f 100644
--- a/certbot-apache/certbot_apache/tests/configurator_test.py
+++ b/certbot-apache/certbot_apache/tests/configurator_test.py
@@ -3,12 +3,12 @@
import os
import shutil
import socket
+import tempfile
import unittest
import mock
# six is used in mock.patch()
import six # pylint: disable=unused-import
-import tempfile
from acme import challenges
@@ -19,7 +19,7 @@ from certbot import errors
from certbot.tests import acme_util
from certbot.tests import util as certbot_util
-from certbot_apache import configurator
+from certbot_apache import apache_util
from certbot_apache import constants
from certbot_apache import parser
from certbot_apache import obj
@@ -34,39 +34,24 @@ class MultipleVhostsTest(util.ApacheTest):
def setUp(self): # pylint: disable=arguments-differ
super(MultipleVhostsTest, self).setUp()
- from certbot_apache.constants import os_constant
- orig_os_constant = os_constant
- def mock_os_constant(key, vhost_path=self.vhost_path):
- """Mock default vhost path"""
- if key == "vhost_root":
- return vhost_path
- else:
- return orig_os_constant(key)
-
- with mock.patch("certbot_apache.constants.os_constant") as mock_c:
- mock_c.side_effect = mock_os_constant
- self.config = util.get_apache_configurator(
- self.config_path, None, self.config_dir, self.work_dir)
- self.config = self.mock_deploy_cert(self.config)
+ 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)
self.vh_truth = util.get_vh_truth(
self.temp_dir, "debian_apache_2_4/multiple_vhosts")
def mock_deploy_cert(self, config):
"""A test for a mock deploy cert"""
- self.config.real_deploy_cert = self.config.deploy_cert
+ config.real_deploy_cert = self.config.deploy_cert
def mocked_deploy_cert(*args, **kwargs):
"""a helper to mock a deployed cert"""
- with mock.patch("certbot_apache.configurator.ApacheConfigurator.enable_mod"):
+ g_mod = "certbot_apache.configurator.ApacheConfigurator.enable_mod"
+ with mock.patch(g_mod):
config.real_deploy_cert(*args, **kwargs)
self.config.deploy_cert = mocked_deploy_cert
return self.config
- def tearDown(self):
- shutil.rmtree(self.temp_dir)
- shutil.rmtree(self.config_dir)
- shutil.rmtree(self.work_dir)
-
@mock.patch("certbot_apache.configurator.ApacheConfigurator.init_augeas")
@mock.patch("certbot_apache.configurator.path_surgery")
def test_prepare_no_install(self, mock_surgery, _init_augeas):
@@ -130,6 +115,10 @@ class MultipleVhostsTest(util.ApacheTest):
# Weak test..
ApacheConfigurator.add_parser_arguments(mock.MagicMock())
+ def test_constant(self):
+ self.assertEqual(self.config.constant("server_root"), "/etc/apache2")
+ self.assertEqual(self.config.constant("nonexistent"), None)
+
@certbot_util.patch_get_utility()
def test_get_all_names(self, mock_getutility):
mock_utility = mock_getutility()
@@ -163,13 +152,12 @@ class MultipleVhostsTest(util.ApacheTest):
self.assertTrue("certbot.demo" in names)
def test_get_bad_path(self):
- from certbot_apache.configurator import get_file_path
- self.assertEqual(get_file_path(None), None)
- self.assertEqual(get_file_path("nonexistent"), None)
+ self.assertEqual(apache_util.get_file_path(None), None)
+ self.assertEqual(apache_util.get_file_path("nonexistent"), None)
self.assertEqual(self.config._create_vhost("nonexistent"), None) # pylint: disable=protected-access
def test_get_aug_internal_path(self):
- from certbot_apache.configurator import get_internal_aug_path
+ from certbot_apache.apache_util import get_internal_aug_path
internal_paths = [
"Virtualhost", "IfModule/VirtualHost", "VirtualHost", "VirtualHost",
"Macro/VirtualHost", "IfModule/VirtualHost", "VirtualHost",
@@ -319,190 +307,23 @@ class MultipleVhostsTest(util.ApacheTest):
# pylint: disable=protected-access
self.assertEqual(len(self.config._non_default_vhosts()), 8)
- @mock.patch("certbot.util.run_script")
- @mock.patch("certbot.util.exe_exists")
- @mock.patch("certbot_apache.parser.subprocess.Popen")
- def test_enable_mod(self, mock_popen, mock_exe_exists, mock_run_script):
- mock_popen().communicate.return_value = ("Define: DUMP_RUN_CFG", "")
- mock_popen().returncode = 0
- mock_exe_exists.return_value = True
-
- self.config.enable_mod("ssl")
- self.assertTrue("ssl_module" in self.config.parser.modules)
- self.assertTrue("mod_ssl.c" in self.config.parser.modules)
-
- self.assertTrue(mock_run_script.called)
-
- def test_enable_mod_unsupported_dirs(self):
- shutil.rmtree(os.path.join(self.config.parser.root, "mods-enabled"))
- self.assertRaises(
- errors.NotSupportedError, self.config.enable_mod, "ssl")
-
- @mock.patch("certbot.util.exe_exists")
- def test_enable_mod_no_disable(self, mock_exe_exists):
- mock_exe_exists.return_value = False
- self.assertRaises(
- errors.MisconfigurationError, self.config.enable_mod, "ssl")
-
- def test_enable_site_already_enabled(self):
- self.assertTrue(self.vh_truth[1].enabled)
- self.config.enable_site(self.vh_truth[1])
-
- def test_enable_site_failure(self):
- self.config.parser.root = "/tmp/nonexistent"
- self.assertRaises(
- errors.NotSupportedError,
- self.config.enable_site,
- obj.VirtualHost("asdf", "afsaf", set(), False, False))
-
- def test_enable_site_nondebian(self):
- mock_c = "certbot_apache.configurator.ApacheConfigurator.conf"
- def conf_side_effect(arg):
- """ Mock function for ApacheConfigurator.conf """
- confvars = {"handle-sites": False}
- if arg in confvars:
- return confvars[arg]
- inc_path = "/path/to/wherever"
- vhost = self.vh_truth[0]
- with mock.patch(mock_c) as mock_conf:
- mock_conf.side_effect = conf_side_effect
- vhost.enabled = False
- vhost.filep = inc_path
- self.assertFalse(self.config.parser.find_dir("Include", inc_path))
- self.assertFalse(
- os.path.dirname(inc_path) in self.config.parser.existing_paths)
- self.config.enable_site(vhost)
- self.assertTrue(self.config.parser.find_dir("Include", inc_path))
- self.assertTrue(
- os.path.dirname(inc_path) in self.config.parser.existing_paths)
- self.assertTrue(
- os.path.basename(inc_path) in self.config.parser.existing_paths[
- os.path.dirname(inc_path)])
-
def test_deploy_cert_enable_new_vhost(self):
# Create
ssl_vhost = self.config.make_vhost_ssl(self.vh_truth[0])
self.config.parser.modules.add("ssl_module")
self.config.parser.modules.add("mod_ssl.c")
+ self.config.parser.modules.add("socache_shmcb_module")
+
self.assertFalse(ssl_vhost.enabled)
self.config.deploy_cert(
"encryption-example.demo", "example/cert.pem", "example/key.pem",
"example/cert_chain.pem", "example/fullchain.pem")
self.assertTrue(ssl_vhost.enabled)
- # Make sure that we don't error out if symlink already exists
- ssl_vhost.enabled = False
- self.assertFalse(ssl_vhost.enabled)
- self.config.deploy_cert(
- "encryption-example.demo", "example/cert.pem", "example/key.pem",
- "example/cert_chain.pem", "example/fullchain.pem")
- self.assertTrue(ssl_vhost.enabled)
-
- def test_deploy_cert_newssl(self):
- self.config = util.get_apache_configurator(
- self.config_path, self.vhost_path, self.config_dir,
- self.work_dir, version=(2, 4, 16))
-
- self.config.parser.modules.add("ssl_module")
- self.config.parser.modules.add("mod_ssl.c")
-
- # Get the default 443 vhost
- self.config.assoc["random.demo"] = self.vh_truth[1]
- self.config = self.mock_deploy_cert(self.config)
- self.config.deploy_cert(
- "random.demo", "example/cert.pem", "example/key.pem",
- "example/cert_chain.pem", "example/fullchain.pem")
- self.config.save()
-
- # Verify ssl_module was enabled.
- self.assertTrue(self.vh_truth[1].enabled)
- self.assertTrue("ssl_module" in self.config.parser.modules)
-
- loc_cert = self.config.parser.find_dir(
- "sslcertificatefile", "example/fullchain.pem",
- self.vh_truth[1].path)
- loc_key = self.config.parser.find_dir(
- "sslcertificateKeyfile", "example/key.pem", self.vh_truth[1].path)
-
- # Verify one directive was found in the correct file
- self.assertEqual(len(loc_cert), 1)
- self.assertEqual(
- configurator.get_file_path(loc_cert[0]),
- self.vh_truth[1].filep)
-
- self.assertEqual(len(loc_key), 1)
- self.assertEqual(
- configurator.get_file_path(loc_key[0]),
- self.vh_truth[1].filep)
-
- def test_deploy_cert_newssl_no_fullchain(self):
- self.config = util.get_apache_configurator(
- self.config_path, self.vhost_path, self.config_dir,
- self.work_dir, version=(2, 4, 16))
- self.config = self.mock_deploy_cert(self.config)
-
- self.config.parser.modules.add("ssl_module")
- self.config.parser.modules.add("mod_ssl.c")
-
- # Get the default 443 vhost
- self.config.assoc["random.demo"] = self.vh_truth[1]
- self.assertRaises(errors.PluginError,
- lambda: self.config.deploy_cert(
- "random.demo", "example/cert.pem",
- "example/key.pem"))
-
- def test_deploy_cert_old_apache_no_chain(self):
- self.config = util.get_apache_configurator(
- self.config_path, self.vhost_path, self.config_dir,
- self.work_dir, version=(2, 4, 7))
- self.config = self.mock_deploy_cert(self.config)
-
- self.config.parser.modules.add("ssl_module")
- self.config.parser.modules.add("mod_ssl.c")
-
- # Get the default 443 vhost
- self.config.assoc["random.demo"] = self.vh_truth[1]
- self.assertRaises(errors.PluginError,
- lambda: self.config.deploy_cert(
- "random.demo", "example/cert.pem",
- "example/key.pem"))
-
- def test_deploy_cert_not_parsed_path(self):
- # Make sure that we add include to root config for vhosts when
- # handle-sites is false
- self.config.parser.modules.add("ssl_module")
- self.config.parser.modules.add("mod_ssl.c")
- tmp_path = os.path.realpath(tempfile.mkdtemp("vhostroot"))
- os.chmod(tmp_path, 0o755)
- mock_p = "certbot_apache.configurator.ApacheConfigurator._get_ssl_vhost_path"
- mock_a = "certbot_apache.parser.ApacheParser.add_include"
- mock_c = "certbot_apache.configurator.ApacheConfigurator.conf"
- orig_conf = self.config.conf
- def conf_side_effect(arg):
- """ Mock function for ApacheConfigurator.conf """
- confvars = {"handle-sites": False}
- if arg in confvars:
- return confvars[arg]
- else:
- return orig_conf("arg")
-
- with mock.patch(mock_c) as mock_conf:
- mock_conf.side_effect = conf_side_effect
- 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
- self.assertTrue(mock_add.called)
- shutil.rmtree(tmp_path)
-
def test_deploy_cert(self):
self.config.parser.modules.add("ssl_module")
self.config.parser.modules.add("mod_ssl.c")
-
+ self.config.parser.modules.add("socache_shmcb_module")
# 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
@@ -531,7 +352,6 @@ class MultipleVhostsTest(util.ApacheTest):
self.assertTrue(
"insert_key_file_path" in find_args(vhostpath,
"SSLCertificateKeyFile"))
-
# pylint: disable=protected-access
self.config._add_dummy_ssl_directives = mock_add_dummy_ssl
@@ -557,17 +377,17 @@ class MultipleVhostsTest(util.ApacheTest):
# Verify one directive was found in the correct file
self.assertEqual(len(loc_cert), 1)
self.assertEqual(
- configurator.get_file_path(loc_cert[0]),
+ apache_util.get_file_path(loc_cert[0]),
self.vh_truth[1].filep)
self.assertEqual(len(loc_key), 1)
self.assertEqual(
- configurator.get_file_path(loc_key[0]),
+ apache_util.get_file_path(loc_key[0]),
self.vh_truth[1].filep)
self.assertEqual(len(loc_chain), 1)
self.assertEqual(
- configurator.get_file_path(loc_chain[0]),
+ apache_util.get_file_path(loc_chain[0]),
self.vh_truth[1].filep)
# One more time for chain directive setting
@@ -877,7 +697,9 @@ class MultipleVhostsTest(util.ApacheTest):
self.assertEqual(mock_restart.call_count, 1)
@mock.patch("certbot_apache.configurator.ApacheConfigurator.restart")
- def test_cleanup(self, mock_restart):
+ @mock.patch("certbot_apache.parser.ApacheParser._get_runtime_cfg")
+ def test_cleanup(self, mock_cfg, mock_restart):
+ mock_cfg.return_value = ""
_, achall1, achall2 = self.get_achalls()
self.config._chall_out.add(achall1) # pylint: disable=protected-access
@@ -890,7 +712,9 @@ class MultipleVhostsTest(util.ApacheTest):
self.assertTrue(mock_restart.called)
@mock.patch("certbot_apache.configurator.ApacheConfigurator.restart")
- def test_cleanup_no_errors(self, mock_restart):
+ @mock.patch("certbot_apache.parser.ApacheParser._get_runtime_cfg")
+ def test_cleanup_no_errors(self, mock_cfg, mock_restart):
+ mock_cfg.return_value = ""
_, achall1, achall2 = self.get_achalls()
self.config._chall_out.add(achall1) # pylint: disable=protected-access
@@ -951,10 +775,9 @@ class MultipleVhostsTest(util.ApacheTest):
self.assertTrue(isinstance(self.config.get_chall_pref(""), list))
def test_install_ssl_options_conf(self):
- from certbot_apache.configurator import install_ssl_options_conf
path = os.path.join(self.work_dir, "test_it")
other_path = os.path.join(self.work_dir, "other_test_it")
- install_ssl_options_conf(path, other_path)
+ self.config.install_ssl_options_conf(path, other_path)
self.assertTrue(os.path.isfile(path))
self.assertTrue(os.path.isfile(other_path))
@@ -994,20 +817,17 @@ class MultipleVhostsTest(util.ApacheTest):
errors.PluginError,
self.config.enhance, "certbot.demo", "unknown_enhancement")
- @mock.patch("certbot.util.run_script")
@mock.patch("certbot.util.exe_exists")
- def test_ocsp_stapling(self, mock_exe, mock_run_script):
+ def test_ocsp_stapling(self, mock_exe):
self.config.parser.update_runtime_variables = mock.Mock()
self.config.parser.modules.add("mod_ssl.c")
+ self.config.parser.modules.add("socache_shmcb_module")
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
self.config.enhance("certbot.demo", "staple-ocsp")
- self.assertTrue("socache_shmcb_module" in self.config.parser.modules)
- self.assertTrue(mock_run_script.called)
-
# Get the ssl vhost for certbot.demo
ssl_vhost = self.config.assoc["certbot.demo"]
@@ -1077,14 +897,13 @@ class MultipleVhostsTest(util.ApacheTest):
def test_http_header_hsts(self, mock_exe, _):
self.config.parser.update_runtime_variables = mock.Mock()
self.config.parser.modules.add("mod_ssl.c")
+ self.config.parser.modules.add("headers_module")
mock_exe.return_value = True
# This will create an ssl vhost for certbot.demo
self.config.enhance("certbot.demo", "ensure-http-header",
"Strict-Transport-Security")
- self.assertTrue("headers_module" in self.config.parser.modules)
-
# Get the ssl vhost for certbot.demo
ssl_vhost = self.config.assoc["certbot.demo"]
@@ -1115,6 +934,8 @@ class MultipleVhostsTest(util.ApacheTest):
def test_http_header_uir(self, mock_exe, _):
self.config.parser.update_runtime_variables = mock.Mock()
self.config.parser.modules.add("mod_ssl.c")
+ self.config.parser.modules.add("headers_module")
+
mock_exe.return_value = True
# This will create an ssl vhost for certbot.demo
@@ -1151,6 +972,7 @@ class MultipleVhostsTest(util.ApacheTest):
@mock.patch("certbot.util.run_script")
@mock.patch("certbot.util.exe_exists")
def test_redirect_well_formed_http(self, mock_exe, _):
+ self.config.parser.modules.add("rewrite_module")
self.config.parser.update_runtime_variables = mock.Mock()
mock_exe.return_value = True
self.config.get_version = mock.Mock(return_value=(2, 2))
@@ -1173,8 +995,6 @@ class MultipleVhostsTest(util.ApacheTest):
self.assertTrue(rw_engine[0].startswith(self.vh_truth[3].path[:-3]))
self.assertTrue(rw_rule[0].startswith(self.vh_truth[3].path[:-3]))
- self.assertTrue("rewrite_module" in self.config.parser.modules)
-
def test_rewrite_rule_exists(self):
# Skip the enable mod
self.config.parser.modules.add("rewrite_module")
@@ -1196,6 +1016,7 @@ class MultipleVhostsTest(util.ApacheTest):
@mock.patch("certbot.util.run_script")
@mock.patch("certbot.util.exe_exists")
def test_redirect_with_existing_rewrite(self, mock_exe, _):
+ self.config.parser.modules.add("rewrite_module")
self.config.parser.update_runtime_variables = mock.Mock()
mock_exe.return_value = True
self.config.get_version = mock.Mock(return_value=(2, 2, 0))
@@ -1228,6 +1049,7 @@ class MultipleVhostsTest(util.ApacheTest):
@mock.patch("certbot.util.run_script")
@mock.patch("certbot.util.exe_exists")
def test_redirect_with_old_https_redirection(self, mock_exe, _):
+ self.config.parser.modules.add("rewrite_module")
self.config.parser.update_runtime_variables = mock.Mock()
mock_exe.return_value = True
self.config.get_version = mock.Mock(return_value=(2, 2, 0))
@@ -1365,6 +1187,57 @@ class MultipleVhostsTest(util.ApacheTest):
self.config.aug.match.side_effect = RuntimeError
self.assertFalse(self.config._check_aug_version())
+ def test_enable_site_nondebian(self):
+ inc_path = "/path/to/wherever"
+ vhost = self.vh_truth[0]
+ vhost.enabled = False
+ vhost.filep = inc_path
+ self.assertFalse(self.config.parser.find_dir("Include", inc_path))
+ self.assertFalse(
+ os.path.dirname(inc_path) in self.config.parser.existing_paths)
+ self.config.enable_site(vhost)
+ self.assertTrue(self.config.parser.find_dir("Include", inc_path))
+ self.assertTrue(
+ os.path.dirname(inc_path) in self.config.parser.existing_paths)
+ self.assertTrue(
+ os.path.basename(inc_path) in self.config.parser.existing_paths[
+ os.path.dirname(inc_path)])
+
+ def test_deploy_cert_not_parsed_path(self):
+ # Make sure that we add include to root config for vhosts when
+ # handle-sites is false
+ self.config.parser.modules.add("ssl_module")
+ self.config.parser.modules.add("mod_ssl.c")
+ self.config.parser.modules.add("socache_shmcb_module")
+ tmp_path = os.path.realpath(tempfile.mkdtemp("vhostroot"))
+ os.chmod(tmp_path, 0o755)
+ mock_p = "certbot_apache.configurator.ApacheConfigurator._get_ssl_vhost_path"
+ mock_a = "certbot_apache.parser.ApacheParser.add_include"
+
+ 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
+ self.assertTrue(mock_add.called)
+ shutil.rmtree(tmp_path)
+
+ @mock.patch("certbot_apache.parser.ApacheParser.parsed_in_original")
+ 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
+ self.assertFalse(mock_parsed.called)
+
+ def test_enable_mod_unsupported(self):
+ self.assertRaises(errors.MisconfigurationError,
+ self.config.enable_mod,
+ "whatever")
+
class AugeasVhostsTest(util.ApacheTest):
"""Test vhosts with illegal names dependent on augeas version."""
# pylint: disable=protected-access
@@ -1378,12 +1251,8 @@ class AugeasVhostsTest(util.ApacheTest):
vhost_root=vr)
self.config = util.get_apache_configurator(
- self.config_path, self.vhost_path, self.config_dir, self.work_dir)
-
- def tearDown(self):
- shutil.rmtree(self.temp_dir)
- shutil.rmtree(self.config_dir)
- shutil.rmtree(self.work_dir)
+ self.config_path, self.vhost_path, self.config_dir,
+ self.work_dir)
def test_choosevhost_with_illegal_name(self):
self.config.aug = mock.MagicMock()
@@ -1461,15 +1330,11 @@ class MultiVhostsTest(util.ApacheTest):
vhost_root=vr)
self.config = util.get_apache_configurator(
- self.config_path, self.vhost_path, self.config_dir, self.work_dir)
+ self.config_path, self.vhost_path,
+ self.config_dir, self.work_dir, conf_vhost_path=self.vhost_path)
self.vh_truth = util.get_vh_truth(
self.temp_dir, "debian_apache_2_4/multi_vhosts")
- def tearDown(self):
- shutil.rmtree(self.temp_dir)
- shutil.rmtree(self.config_dir)
- shutil.rmtree(self.work_dir)
-
def test_make_vhost_ssl(self):
ssl_vhost = self.config.make_vhost_ssl(self.vh_truth[1])
@@ -1569,11 +1434,11 @@ class InstallSslOptionsConfTest(util.ApacheTest):
self.config_path, self.vhost_path, self.config_dir, self.work_dir)
def _call(self):
- from certbot_apache.configurator import install_ssl_options_conf
- install_ssl_options_conf(self.config.mod_ssl_conf, self.config.updated_mod_ssl_conf_digest)
+ self.config.install_ssl_options_conf(self.config.mod_ssl_conf,
+ self.config.updated_mod_ssl_conf_digest)
def _current_ssl_options_hash(self):
- return crypto_util.sha256sum(constants.os_constant("MOD_SSL_CONF_SRC"))
+ return crypto_util.sha256sum(self.config.constant("MOD_SSL_CONF_SRC"))
def _assert_current_file(self):
self.assertTrue(os.path.isfile(self.config.mod_ssl_conf))
@@ -1608,7 +1473,8 @@ class InstallSslOptionsConfTest(util.ApacheTest):
self._call()
self.assertFalse(mock_logger.warning.called)
self.assertTrue(os.path.isfile(self.config.mod_ssl_conf))
- self.assertEqual(crypto_util.sha256sum(constants.os_constant("MOD_SSL_CONF_SRC")),
+ self.assertEqual(crypto_util.sha256sum(
+ self.config.constant("MOD_SSL_CONF_SRC")),
self._current_ssl_options_hash())
self.assertNotEqual(crypto_util.sha256sum(self.config.mod_ssl_conf),
self._current_ssl_options_hash())
@@ -1623,7 +1489,8 @@ class InstallSslOptionsConfTest(util.ApacheTest):
self.assertEqual(mock_logger.warning.call_args[0][0],
"%s has been manually modified; updated file "
"saved to %s. We recommend updating %s for security purposes.")
- self.assertEqual(crypto_util.sha256sum(constants.os_constant("MOD_SSL_CONF_SRC")),
+ self.assertEqual(crypto_util.sha256sum(
+ self.config.constant("MOD_SSL_CONF_SRC")),
self._current_ssl_options_hash())
# only print warning once
with mock.patch("certbot.plugins.common.logger") as mock_logger:
diff --git a/certbot-apache/certbot_apache/tests/constants_test.py b/certbot-apache/certbot_apache/tests/constants_test.py
deleted file mode 100644
index 5ab324101..000000000
--- a/certbot-apache/certbot_apache/tests/constants_test.py
+++ /dev/null
@@ -1,44 +0,0 @@
-"""Test for certbot_apache.configurator."""
-
-import mock
-import unittest
-
-from certbot_apache import constants
-
-
-class ConstantsTest(unittest.TestCase):
-
- @mock.patch("certbot.util.get_os_info")
- def test_get_debian_value(self, os_info):
- os_info.return_value = ('Debian', '', '')
- self.assertEqual(constants.os_constant("vhost_root"),
- "/etc/apache2/sites-available")
-
- @mock.patch("certbot.util.get_os_info")
- def test_get_centos_value(self, os_info):
- os_info.return_value = ('CentOS Linux', '', '')
- self.assertEqual(constants.os_constant("vhost_root"),
- "/etc/httpd/conf.d")
-
- @mock.patch("certbot.util.get_systemd_os_like")
- @mock.patch("certbot.util.get_os_info")
- def test_get_default_values(self, os_info, os_like):
- os_info.return_value = ('Nonexistent Linux', '', '')
- os_like.return_value = {}
- self.assertFalse(constants.os_constant("handle_mods"))
- self.assertEqual(constants.os_constant("server_root"), "/etc/apache2")
- self.assertEqual(constants.os_constant("vhost_root"),
- "/etc/apache2/sites-available")
-
- @mock.patch("certbot.util.get_systemd_os_like")
- @mock.patch("certbot.util.get_os_info")
- def test_get_darwin_like_values(self, os_info, os_like):
- os_info.return_value = ('Nonexistent Linux', '', '')
- os_like.return_value = ["something", "nonexistent", "darwin"]
- self.assertFalse(constants.os_constant("enmod"))
- self.assertEqual(constants.os_constant("vhost_root"),
- "/etc/apache2/other")
-
-
-if __name__ == "__main__":
- unittest.main() # pragma: no cover
diff --git a/certbot-apache/certbot_apache/tests/debian_test.py b/certbot-apache/certbot_apache/tests/debian_test.py
new file mode 100644
index 000000000..a648101e9
--- /dev/null
+++ b/certbot-apache/certbot_apache/tests/debian_test.py
@@ -0,0 +1,209 @@
+"""Test for certbot_apache.configurator for Debian overrides"""
+import os
+import shutil
+import unittest
+
+import mock
+
+from certbot import errors
+
+from certbot_apache import apache_util
+from certbot_apache import obj
+from certbot_apache.tests import util
+
+
+class MultipleVhostsTestDebian(util.ApacheTest):
+ """Multiple vhost tests for Debian family of distros"""
+
+ _multiprocess_can_split_ = True
+
+ def setUp(self): # pylint: disable=arguments-differ
+ super(MultipleVhostsTestDebian, self).setUp()
+ self.config = util.get_apache_configurator(
+ self.config_path, None, self.config_dir, self.work_dir,
+ os_info="debian")
+ self.config = self.mock_deploy_cert(self.config)
+ self.vh_truth = util.get_vh_truth(self.temp_dir,
+ "debian_apache_2_4/multiple_vhosts")
+
+ def mock_deploy_cert(self, config):
+ """A test for a mock deploy cert"""
+ config.real_deploy_cert = self.config.deploy_cert
+
+ def mocked_deploy_cert(*args, **kwargs):
+ """a helper to mock a deployed cert"""
+ g_mod = "certbot_apache.configurator.ApacheConfigurator.enable_mod"
+ d_mod = "certbot_apache.override_debian.DebianConfigurator.enable_mod"
+ with mock.patch(g_mod):
+ with mock.patch(d_mod):
+ config.real_deploy_cert(*args, **kwargs)
+ self.config.deploy_cert = mocked_deploy_cert
+ return self.config
+
+ def test_enable_mod_unsupported_dirs(self):
+ shutil.rmtree(os.path.join(self.config.parser.root, "mods-enabled"))
+ self.assertRaises(
+ errors.NotSupportedError, self.config.enable_mod, "ssl")
+
+ @mock.patch("certbot.util.run_script")
+ @mock.patch("certbot.util.exe_exists")
+ @mock.patch("certbot_apache.parser.subprocess.Popen")
+ def test_enable_mod(self, mock_popen, mock_exe_exists, mock_run_script):
+ mock_popen().communicate.return_value = ("Define: DUMP_RUN_CFG", "")
+ mock_popen().returncode = 0
+ mock_exe_exists.return_value = True
+
+ self.config.enable_mod("ssl")
+ self.assertTrue("ssl_module" in self.config.parser.modules)
+ self.assertTrue("mod_ssl.c" in self.config.parser.modules)
+
+ self.assertTrue(mock_run_script.called)
+
+ def test_deploy_cert_enable_new_vhost(self):
+ # Create
+ ssl_vhost = self.config.make_vhost_ssl(self.vh_truth[0])
+ self.config.parser.modules.add("ssl_module")
+ self.config.parser.modules.add("mod_ssl.c")
+ self.assertFalse(ssl_vhost.enabled)
+ self.config.deploy_cert(
+ "encryption-example.demo", "example/cert.pem", "example/key.pem",
+ "example/cert_chain.pem", "example/fullchain.pem")
+ self.assertTrue(ssl_vhost.enabled)
+ # Make sure that we don't error out if symlink already exists
+ ssl_vhost.enabled = False
+ self.assertFalse(ssl_vhost.enabled)
+ self.config.deploy_cert(
+ "encryption-example.demo", "example/cert.pem", "example/key.pem",
+ "example/cert_chain.pem", "example/fullchain.pem")
+ self.assertTrue(ssl_vhost.enabled)
+
+ def test_enable_site_failure(self):
+ self.config.parser.root = "/tmp/nonexistent"
+ with mock.patch("os.path.isdir") as mock_dir:
+ mock_dir.return_value = True
+ with mock.patch("os.path.islink") as mock_link:
+ mock_link.return_value = False
+ self.assertRaises(
+ errors.NotSupportedError,
+ self.config.enable_site,
+ obj.VirtualHost("asdf", "afsaf", set(), False, False))
+
+ def test_deploy_cert_newssl(self):
+ self.config = util.get_apache_configurator(
+ self.config_path, self.vhost_path, self.config_dir,
+ self.work_dir, version=(2, 4, 16))
+ self.config = self.mock_deploy_cert(self.config)
+ self.config.parser.modules.add("ssl_module")
+ self.config.parser.modules.add("mod_ssl.c")
+
+ # Get the default 443 vhost
+ self.config.assoc["random.demo"] = self.vh_truth[1]
+ self.config.deploy_cert(
+ "random.demo", "example/cert.pem", "example/key.pem",
+ "example/cert_chain.pem", "example/fullchain.pem")
+ self.config.save()
+
+ # Verify ssl_module was enabled.
+ self.assertTrue(self.vh_truth[1].enabled)
+ self.assertTrue("ssl_module" in self.config.parser.modules)
+
+ loc_cert = self.config.parser.find_dir(
+ "sslcertificatefile", "example/fullchain.pem",
+ self.vh_truth[1].path)
+ loc_key = self.config.parser.find_dir(
+ "sslcertificateKeyfile", "example/key.pem", self.vh_truth[1].path)
+
+ # Verify one directive was found in the correct file
+ self.assertEqual(len(loc_cert), 1)
+ self.assertEqual(
+ apache_util.get_file_path(loc_cert[0]),
+ self.vh_truth[1].filep)
+
+ self.assertEqual(len(loc_key), 1)
+ self.assertEqual(
+ apache_util.get_file_path(loc_key[0]),
+ self.vh_truth[1].filep)
+
+ def test_deploy_cert_newssl_no_fullchain(self):
+ self.config = util.get_apache_configurator(
+ self.config_path, self.vhost_path, self.config_dir,
+ self.work_dir, version=(2, 4, 16))
+ self.config = self.mock_deploy_cert(self.config)
+ self.config.parser.modules.add("ssl_module")
+ self.config.parser.modules.add("mod_ssl.c")
+
+ # Get the default 443 vhost
+ self.config.assoc["random.demo"] = self.vh_truth[1]
+ self.assertRaises(errors.PluginError,
+ lambda: self.config.deploy_cert(
+ "random.demo", "example/cert.pem",
+ "example/key.pem"))
+
+ def test_deploy_cert_old_apache_no_chain(self):
+ self.config = util.get_apache_configurator(
+ self.config_path, self.vhost_path, self.config_dir,
+ self.work_dir, version=(2, 4, 7))
+ self.config = self.mock_deploy_cert(self.config)
+ self.config.parser.modules.add("ssl_module")
+ self.config.parser.modules.add("mod_ssl.c")
+
+ # Get the default 443 vhost
+ self.config.assoc["random.demo"] = self.vh_truth[1]
+ self.assertRaises(errors.PluginError,
+ lambda: self.config.deploy_cert(
+ "random.demo", "example/cert.pem",
+ "example/key.pem"))
+
+ @mock.patch("certbot.util.run_script")
+ @mock.patch("certbot.util.exe_exists")
+ def test_ocsp_stapling_enable_mod(self, mock_exe, _):
+ self.config.parser.update_runtime_variables = mock.Mock()
+ self.config.parser.modules.add("mod_ssl.c")
+ self.config.get_version = mock.Mock(return_value=(2, 4, 7))
+ mock_exe.return_value = True
+ self.config.enhance("certbot.demo", "staple-ocsp")
+ self.assertTrue("socache_shmcb_module" in self.config.parser.modules)
+
+ @mock.patch("certbot.util.run_script")
+ @mock.patch("certbot.util.exe_exists")
+ def test_ensure_http_header_enable_mod(self, mock_exe, _):
+ self.config.parser.update_runtime_variables = mock.Mock()
+ self.config.parser.modules.add("mod_ssl.c")
+ mock_exe.return_value = True
+
+ # This will create an ssl vhost for certbot.demo
+ self.config.enhance("certbot.demo", "ensure-http-header",
+ "Strict-Transport-Security")
+ self.assertTrue("headers_module" in self.config.parser.modules)
+
+ @mock.patch("certbot.util.run_script")
+ @mock.patch("certbot.util.exe_exists")
+ def test_redirect_enable_mod(self, mock_exe, _):
+ self.config.parser.update_runtime_variables = mock.Mock()
+ mock_exe.return_value = True
+ self.config.get_version = mock.Mock(return_value=(2, 2))
+ # This will create an ssl vhost for certbot.demo
+ self.config.enhance("certbot.demo", "redirect")
+ self.assertTrue("rewrite_module" in self.config.parser.modules)
+
+ def test_enable_site_already_enabled(self):
+ self.assertTrue(self.vh_truth[1].enabled)
+ self.config.enable_site(self.vh_truth[1])
+
+ def test_enable_site_call_parent(self):
+ with mock.patch(
+ "certbot_apache.configurator.ApacheConfigurator.enable_site") as e_s:
+ self.config.parser.root = "/tmp/nonexistent"
+ vh = self.vh_truth[0]
+ vh.enabled = False
+ self.config.enable_site(vh)
+ self.assertTrue(e_s.called)
+
+ @mock.patch("certbot.util.exe_exists")
+ def test_enable_mod_no_disable(self, mock_exe_exists):
+ mock_exe_exists.return_value = False
+ self.assertRaises(
+ errors.MisconfigurationError, self.config.enable_mod, "ssl")
+
+if __name__ == "__main__":
+ unittest.main() # pragma: no cover
diff --git a/certbot-apache/certbot_apache/tests/entrypoint_test.py b/certbot-apache/certbot_apache/tests/entrypoint_test.py
new file mode 100644
index 000000000..c04611465
--- /dev/null
+++ b/certbot-apache/certbot_apache/tests/entrypoint_test.py
@@ -0,0 +1,41 @@
+"""Test for certbot_apache.entrypoint for override class resolution"""
+import unittest
+
+import mock
+
+from certbot_apache import configurator
+from certbot_apache import entrypoint
+
+class EntryPointTest(unittest.TestCase):
+ """Entrypoint tests"""
+
+ _multiprocess_can_split_ = True
+
+ def test_get_configurator(self):
+
+ with mock.patch("certbot.util.get_os_info") as mock_info:
+ for distro in entrypoint.OVERRIDE_CLASSES.keys():
+ mock_info.return_value = (distro, "whatever")
+ self.assertEqual(entrypoint.get_configurator(),
+ entrypoint.OVERRIDE_CLASSES[distro])
+
+ def test_nonexistent_like(self):
+ with mock.patch("certbot.util.get_os_info") as mock_info:
+ mock_info.return_value = ("nonexistent", "irrelevant")
+ with mock.patch("certbot.util.get_systemd_os_like") as mock_like:
+ for like in entrypoint.OVERRIDE_CLASSES.keys():
+ mock_like.return_value = [like]
+ self.assertEqual(entrypoint.get_configurator(),
+ entrypoint.OVERRIDE_CLASSES[like])
+
+ def test_nonexistent_generic(self):
+ with mock.patch("certbot.util.get_os_info") as mock_info:
+ mock_info.return_value = ("nonexistent", "irrelevant")
+ with mock.patch("certbot.util.get_systemd_os_like") as mock_like:
+ mock_like.return_value = ["unknonwn"]
+ self.assertEqual(entrypoint.get_configurator(),
+ configurator.ApacheConfigurator)
+
+
+if __name__ == "__main__":
+ unittest.main() # pragma: no cover
diff --git a/certbot-apache/certbot_apache/tests/gentoo_test.py b/certbot-apache/certbot_apache/tests/gentoo_test.py
new file mode 100644
index 000000000..0f2b96818
--- /dev/null
+++ b/certbot-apache/certbot_apache/tests/gentoo_test.py
@@ -0,0 +1,86 @@
+"""Test for certbot_apache.configurator for Gentoo overrides"""
+import os
+import unittest
+
+from certbot_apache import override_gentoo
+from certbot_apache import obj
+from certbot_apache.tests import util
+
+def get_vh_truth(temp_dir, config_name):
+ """Return the ground truth for the specified directory."""
+ prefix = os.path.join(
+ temp_dir, config_name, "apache2/vhosts.d")
+
+ aug_pre = "/files" + prefix
+ vh_truth = [
+ obj.VirtualHost(
+ os.path.join(prefix, "gentoo.example.com.conf"),
+ os.path.join(aug_pre, "gentoo.example.com.conf/VirtualHost"),
+ set([obj.Addr.fromstring("*:80")]),
+ False, True, "gentoo.example.com"),
+ obj.VirtualHost(
+ os.path.join(prefix, "00_default_vhost.conf"),
+ os.path.join(aug_pre, "00_default_vhost.conf/IfDefine/VirtualHost"),
+ set([obj.Addr.fromstring("*:80")]),
+ False, True, "localhost"),
+ obj.VirtualHost(
+ os.path.join(prefix, "00_default_ssl_vhost.conf"),
+ os.path.join(aug_pre,
+ "00_default_ssl_vhost.conf" +
+ "/IfDefine/IfDefine/IfModule/VirtualHost"),
+ set([obj.Addr.fromstring("_default_:443")]),
+ True, True, "localhost")
+ ]
+ return vh_truth
+
+class MultipleVhostsTestGentoo(util.ApacheTest):
+ """Multiple vhost tests for non-debian distro"""
+
+ _multiprocess_can_split_ = True
+
+ def setUp(self): # pylint: disable=arguments-differ
+ test_dir = "gentoo_apache/apache"
+ config_root = "gentoo_apache/apache/apache2"
+ vhost_root = "gentoo_apache/apache/apache2/vhosts.d"
+ super(MultipleVhostsTestGentoo, self).setUp(test_dir=test_dir,
+ config_root=config_root,
+ vhost_root=vhost_root)
+
+ self.config = util.get_apache_configurator(
+ self.config_path, self.vhost_path, self.config_dir, self.work_dir,
+ os_info="gentoo")
+ self.vh_truth = get_vh_truth(
+ self.temp_dir, "gentoo_apache/apache")
+
+ def test_get_parser(self):
+ self.assertTrue(isinstance(self.config.parser,
+ override_gentoo.GentooParser))
+
+ def test_get_virtual_hosts(self):
+ """Make sure all vhosts are being properly found."""
+ vhs = self.config.get_virtual_hosts()
+ self.assertEqual(len(vhs), 3)
+ found = 0
+
+ for vhost in vhs:
+ for gentoo_truth in self.vh_truth:
+ if vhost == gentoo_truth:
+ found += 1
+ break
+ else:
+ raise Exception("Missed: %s" % vhost) # pragma: no cover
+ self.assertEqual(found, 3)
+
+ def test_get_sysconfig_vars(self):
+ """Make sure we read the Gentoo APACHE2_OPTS variable correctly"""
+ defines = ['DEFAULT_VHOST', 'INFO',
+ 'SSL', 'SSL_DEFAULT_VHOST', 'LANGUAGE']
+ self.config.parser.apacheconfig_filep = os.path.realpath(
+ os.path.join(self.config.parser.root, "../conf.d/apache2"))
+ self.config.parser.variables = {}
+ self.config.parser.update_runtime_variables()
+ for define in defines:
+ self.assertTrue(define in self.config.parser.variables.keys())
+
+if __name__ == "__main__":
+ unittest.main() # pragma: no cover
diff --git a/certbot-apache/certbot_apache/tests/parser_test.py b/certbot-apache/certbot_apache/tests/parser_test.py
index 38c5b29c7..a9eb129c2 100644
--- a/certbot-apache/certbot_apache/tests/parser_test.py
+++ b/certbot-apache/certbot_apache/tests/parser_test.py
@@ -120,17 +120,18 @@ class BasicParserTest(util.ParserTest):
@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):
+ def test_parse_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()
+ self.parser.parse_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.find_dir")
@mock.patch("certbot_apache.parser.ApacheParser._get_runtime_cfg")
- def test_update_runtime_variables(self, mock_cfg):
- mock_cfg.return_value = (
+ def test_update_runtime_variables(self, mock_cfg, _):
+ define_val = (
'ServerRoot: "/etc/apache2"\n'
'Main DocumentRoot: "/var/www"\n'
'Main ErrorLog: "/var/log/apache2/error.log"\n'
@@ -147,11 +148,113 @@ class BasicParserTest(util.ParserTest):
'User: name="www-data" id=33 not_used\n'
'Group: name="www-data" id=33 not_used\n'
)
+ inc_val = (
+ 'Included configuration files:\n'
+ ' (*) /etc/apache2/apache2.conf\n'
+ ' (146) /etc/apache2/mods-enabled/access_compat.load\n'
+ ' (146) /etc/apache2/mods-enabled/alias.load\n'
+ ' (146) /etc/apache2/mods-enabled/auth_basic.load\n'
+ ' (146) /etc/apache2/mods-enabled/authn_core.load\n'
+ ' (146) /etc/apache2/mods-enabled/authn_file.load\n'
+ ' (146) /etc/apache2/mods-enabled/authz_core.load\n'
+ ' (146) /etc/apache2/mods-enabled/authz_host.load\n'
+ ' (146) /etc/apache2/mods-enabled/authz_user.load\n'
+ ' (146) /etc/apache2/mods-enabled/autoindex.load\n'
+ ' (146) /etc/apache2/mods-enabled/deflate.load\n'
+ ' (146) /etc/apache2/mods-enabled/dir.load\n'
+ ' (146) /etc/apache2/mods-enabled/env.load\n'
+ ' (146) /etc/apache2/mods-enabled/filter.load\n'
+ ' (146) /etc/apache2/mods-enabled/mime.load\n'
+ ' (146) /etc/apache2/mods-enabled/mpm_event.load\n'
+ ' (146) /etc/apache2/mods-enabled/negotiation.load\n'
+ ' (146) /etc/apache2/mods-enabled/reqtimeout.load\n'
+ ' (146) /etc/apache2/mods-enabled/setenvif.load\n'
+ ' (146) /etc/apache2/mods-enabled/socache_shmcb.load\n'
+ ' (146) /etc/apache2/mods-enabled/ssl.load\n'
+ ' (146) /etc/apache2/mods-enabled/status.load\n'
+ ' (147) /etc/apache2/mods-enabled/alias.conf\n'
+ ' (147) /etc/apache2/mods-enabled/autoindex.conf\n'
+ ' (147) /etc/apache2/mods-enabled/deflate.conf\n'
+ )
+ mod_val = (
+ 'Loaded Modules:\n'
+ ' core_module (static)\n'
+ ' so_module (static)\n'
+ ' watchdog_module (static)\n'
+ ' http_module (static)\n'
+ ' log_config_module (static)\n'
+ ' logio_module (static)\n'
+ ' version_module (static)\n'
+ ' unixd_module (static)\n'
+ ' access_compat_module (shared)\n'
+ ' alias_module (shared)\n'
+ ' auth_basic_module (shared)\n'
+ ' authn_core_module (shared)\n'
+ ' authn_file_module (shared)\n'
+ ' authz_core_module (shared)\n'
+ ' authz_host_module (shared)\n'
+ ' authz_user_module (shared)\n'
+ ' autoindex_module (shared)\n'
+ ' deflate_module (shared)\n'
+ ' dir_module (shared)\n'
+ ' env_module (shared)\n'
+ ' filter_module (shared)\n'
+ ' mime_module (shared)\n'
+ ' mpm_event_module (shared)\n'
+ ' negotiation_module (shared)\n'
+ ' reqtimeout_module (shared)\n'
+ ' setenvif_module (shared)\n'
+ ' socache_shmcb_module (shared)\n'
+ ' ssl_module (shared)\n'
+ ' status_module (shared)\n'
+ )
+
+ def mock_get_vars(cmd):
+ """Mock command output"""
+ if cmd[-1] == "DUMP_RUN_CFG":
+ return define_val
+ elif cmd[-1] == "DUMP_INCLUDES":
+ return inc_val
+ elif cmd[-1] == "DUMP_MODULES":
+ return mod_val
+
+ mock_cfg.side_effect = mock_get_vars
+
expected_vars = {"TEST": "", "U_MICH": "", "TLS": "443",
"example_path": "Documents/path"}
- self.parser.update_runtime_variables()
- self.assertEqual(self.parser.variables, expected_vars)
+ self.parser.modules = set()
+ with mock.patch(
+ "certbot_apache.parser.ApacheParser.parse_file") as mock_parse:
+ self.parser.update_runtime_variables()
+ self.assertEqual(self.parser.variables, expected_vars)
+ self.assertEqual(len(self.parser.modules), 58)
+ # None of the includes in inc_val should be in parsed paths.
+ # Make sure we tried to include them all.
+ self.assertEqual(mock_parse.call_count, 25)
+
+ @mock.patch("certbot_apache.parser.ApacheParser.find_dir")
+ @mock.patch("certbot_apache.parser.ApacheParser._get_runtime_cfg")
+ def test_update_runtime_variables_alt_values(self, mock_cfg, _):
+ inc_val = (
+ 'Included configuration files:\n'
+ ' (*) {0}\n'
+ ' (146) /etc/apache2/mods-enabled/access_compat.load\n'
+ ' (146) {1}/mods-enabled/alias.load\n'
+ ).format(self.parser.loc["root"],
+ os.path.dirname(self.parser.loc["root"]))
+
+ mock_cfg.return_value = inc_val
+ self.parser.modules = set()
+
+ with mock.patch(
+ "certbot_apache.parser.ApacheParser.parse_file") as mock_parse:
+ self.parser.update_runtime_variables()
+ # No matching modules should have been found
+ self.assertEqual(len(self.parser.modules), 0)
+ # Only one of the three includes do not exist in already parsed
+ # path derived from root configuration Include statements
+ self.assertEqual(mock_parse.call_count, 1)
@mock.patch("certbot_apache.parser.ApacheParser._get_runtime_cfg")
def test_update_runtime_vars_bad_output(self, mock_cfg):
@@ -162,7 +265,7 @@ class BasicParserTest(util.ParserTest):
self.assertRaises(
errors.PluginError, self.parser.update_runtime_variables)
- @mock.patch("certbot_apache.constants.os_constant")
+ @mock.patch("certbot_apache.configurator.ApacheConfigurator.constant")
@mock.patch("certbot_apache.parser.subprocess.Popen")
def test_update_runtime_vars_bad_ctl(self, mock_popen, mock_const):
mock_popen.side_effect = OSError
@@ -198,7 +301,7 @@ class ParserInitTest(util.ApacheTest):
self.assertRaises(
errors.PluginError,
ApacheParser, self.aug, os.path.relpath(self.config_path),
- "/dummy/vhostpath", version=(2, 2, 22))
+ "/dummy/vhostpath", version=(2, 2, 22), configurator=self.config)
def test_root_normalized(self):
from certbot_apache.parser import ApacheParser
@@ -210,7 +313,7 @@ class ParserInitTest(util.ApacheTest):
"debian_apache_2_4/////multiple_vhosts/../multiple_vhosts/apache2")
parser = ApacheParser(self.aug, path,
- "/dummy/vhostpath")
+ "/dummy/vhostpath", configurator=self.config)
self.assertEqual(parser.root, self.config_path)
@@ -220,7 +323,7 @@ class ParserInitTest(util.ApacheTest):
"update_runtime_variables"):
parser = ApacheParser(
self.aug, os.path.relpath(self.config_path),
- "/dummy/vhostpath")
+ "/dummy/vhostpath", configurator=self.config)
self.assertEqual(parser.root, self.config_path)
@@ -230,7 +333,7 @@ class ParserInitTest(util.ApacheTest):
"update_runtime_variables"):
parser = ApacheParser(
self.aug, self.config_path + os.path.sep,
- "/dummy/vhostpath")
+ "/dummy/vhostpath", configurator=self.config)
self.assertEqual(parser.root, self.config_path)
diff --git a/certbot-apache/certbot_apache/tests/testdata/centos7_apache/apache/httpd/conf.d/README b/certbot-apache/certbot_apache/tests/testdata/centos7_apache/apache/httpd/conf.d/README
new file mode 100644
index 000000000..f5e96615a
--- /dev/null
+++ b/certbot-apache/certbot_apache/tests/testdata/centos7_apache/apache/httpd/conf.d/README
@@ -0,0 +1,9 @@
+
+This directory holds configuration files for the Apache HTTP Server;
+any files in this directory which have the ".conf" extension will be
+processed as httpd configuration files. The directory is used in
+addition to the directory /etc/httpd/conf.modules.d/, which contains
+configuration files necessary to load modules.
+
+Files are processed in alphabetical order.
+
diff --git a/certbot-apache/certbot_apache/tests/testdata/centos7_apache/apache/httpd/conf.d/autoindex.conf b/certbot-apache/certbot_apache/tests/testdata/centos7_apache/apache/httpd/conf.d/autoindex.conf
new file mode 100644
index 000000000..a85cf5dca
--- /dev/null
+++ b/certbot-apache/certbot_apache/tests/testdata/centos7_apache/apache/httpd/conf.d/autoindex.conf
@@ -0,0 +1,94 @@
+#
+# Directives controlling the display of server-generated directory listings.
+#
+# Required modules: mod_authz_core, mod_authz_host,
+# mod_autoindex, mod_alias
+#
+# To see the listing of a directory, the Options directive for the
+# directory must include "Indexes", and the directory must not contain
+# a file matching those listed in the DirectoryIndex directive.
+#
+
+#
+# IndexOptions: Controls the appearance of server-generated directory
+# listings.
+#
+IndexOptions FancyIndexing HTMLTable VersionSort
+
+# We include the /icons/ alias for FancyIndexed directory listings. If
+# you do not use FancyIndexing, you may comment this out.
+#
+Alias /icons/ "/usr/share/httpd/icons/"
+
+
+ Options Indexes MultiViews FollowSymlinks
+ AllowOverride None
+ Require all granted
+
+
+#
+# AddIcon* directives tell the server which icon to show for different
+# files or filename extensions. These are only displayed for
+# FancyIndexed directories.
+#
+AddIconByEncoding (CMP,/icons/compressed.gif) x-compress x-gzip
+
+AddIconByType (TXT,/icons/text.gif) text/*
+AddIconByType (IMG,/icons/image2.gif) image/*
+AddIconByType (SND,/icons/sound2.gif) audio/*
+AddIconByType (VID,/icons/movie.gif) video/*
+
+AddIcon /icons/binary.gif .bin .exe
+AddIcon /icons/binhex.gif .hqx
+AddIcon /icons/tar.gif .tar
+AddIcon /icons/world2.gif .wrl .wrl.gz .vrml .vrm .iv
+AddIcon /icons/compressed.gif .Z .z .tgz .gz .zip
+AddIcon /icons/a.gif .ps .ai .eps
+AddIcon /icons/layout.gif .html .shtml .htm .pdf
+AddIcon /icons/text.gif .txt
+AddIcon /icons/c.gif .c
+AddIcon /icons/p.gif .pl .py
+AddIcon /icons/f.gif .for
+AddIcon /icons/dvi.gif .dvi
+AddIcon /icons/uuencoded.gif .uu
+AddIcon /icons/script.gif .conf .sh .shar .csh .ksh .tcl
+AddIcon /icons/tex.gif .tex
+AddIcon /icons/bomb.gif /core
+AddIcon /icons/bomb.gif */core.*
+
+AddIcon /icons/back.gif ..
+AddIcon /icons/hand.right.gif README
+AddIcon /icons/folder.gif ^^DIRECTORY^^
+AddIcon /icons/blank.gif ^^BLANKICON^^
+
+#
+# DefaultIcon is which icon to show for files which do not have an icon
+# explicitly set.
+#
+DefaultIcon /icons/unknown.gif
+
+#
+# AddDescription allows you to place a short description after a file in
+# server-generated indexes. These are only displayed for FancyIndexed
+# directories.
+# Format: AddDescription "description" filename
+#
+#AddDescription "GZIP compressed document" .gz
+#AddDescription "tar archive" .tar
+#AddDescription "GZIP compressed tar archive" .tgz
+
+#
+# ReadmeName is the name of the README file the server will look for by
+# default, and append to directory listings.
+#
+# HeaderName is the name of a file which should be prepended to
+# directory indexes.
+ReadmeName README.html
+HeaderName HEADER.html
+
+#
+# IndexIgnore is a set of filenames which directory indexing should ignore
+# and not include in the listing. Shell-style wildcarding is permitted.
+#
+IndexIgnore .??* *~ *# HEADER* README* RCS CVS *,v *,t
+
diff --git a/certbot-apache/certbot_apache/tests/testdata/centos7_apache/apache/httpd/conf.d/centos.example.com.conf b/certbot-apache/certbot_apache/tests/testdata/centos7_apache/apache/httpd/conf.d/centos.example.com.conf
new file mode 100644
index 000000000..de7ac2777
--- /dev/null
+++ b/certbot-apache/certbot_apache/tests/testdata/centos7_apache/apache/httpd/conf.d/centos.example.com.conf
@@ -0,0 +1,7 @@
+
+ ServerName centos.example.com
+ ServerAdmin webmaster@localhost
+ DocumentRoot /var/www/html
+ ErrorLog ${APACHE_LOG_DIR}/error.log
+ CustomLog ${APACHE_LOG_DIR}/access.log combined
+
diff --git a/certbot-apache/certbot_apache/tests/testdata/centos7_apache/apache/httpd/conf.d/ssl.conf b/certbot-apache/certbot_apache/tests/testdata/centos7_apache/apache/httpd/conf.d/ssl.conf
new file mode 100644
index 000000000..6e2502e9a
--- /dev/null
+++ b/certbot-apache/certbot_apache/tests/testdata/centos7_apache/apache/httpd/conf.d/ssl.conf
@@ -0,0 +1,211 @@
+#
+# When we also provide SSL we have to listen to the
+# the HTTPS port in addition.
+#
+Listen 443 https
+
+##
+## SSL Global Context
+##
+## All SSL configuration in this context applies both to
+## the main server and all SSL-enabled virtual hosts.
+##
+
+# Pass Phrase Dialog:
+# Configure the pass phrase gathering process.
+# The filtering dialog program (`builtin' is a internal
+# terminal dialog) has to provide the pass phrase on stdout.
+SSLPassPhraseDialog exec:/usr/libexec/httpd-ssl-pass-dialog
+
+# Inter-Process Session Cache:
+# Configure the SSL Session Cache: First the mechanism
+# to use and second the expiring timeout (in seconds).
+SSLSessionCache shmcb:/run/httpd/sslcache(512000)
+SSLSessionCacheTimeout 300
+
+# Pseudo Random Number Generator (PRNG):
+# Configure one or more sources to seed the PRNG of the
+# SSL library. The seed data should be of good random quality.
+# WARNING! On some platforms /dev/random blocks if not enough entropy
+# is available. This means you then cannot use the /dev/random device
+# because it would lead to very long connection times (as long as
+# it requires to make more entropy available). But usually those
+# platforms additionally provide a /dev/urandom device which doesn't
+# block. So, if available, use this one instead. Read the mod_ssl User
+# Manual for more details.
+SSLRandomSeed startup file:/dev/urandom 256
+SSLRandomSeed connect builtin
+#SSLRandomSeed startup file:/dev/random 512
+#SSLRandomSeed connect file:/dev/random 512
+#SSLRandomSeed connect file:/dev/urandom 512
+
+#
+# Use "SSLCryptoDevice" to enable any supported hardware
+# accelerators. Use "openssl engine -v" to list supported
+# engine names. NOTE: If you enable an accelerator and the
+# server does not start, consult the error logs and ensure
+# your accelerator is functioning properly.
+#
+SSLCryptoDevice builtin
+#SSLCryptoDevice ubsec
+
+##
+## SSL Virtual Host Context
+##
+
+
+
+# General setup for the virtual host, inherited from global configuration
+#DocumentRoot "/var/www/html"
+#ServerName www.example.com:443
+
+# Use separate log files for the SSL virtual host; note that LogLevel
+# is not inherited from httpd.conf.
+ErrorLog logs/ssl_error_log
+TransferLog logs/ssl_access_log
+LogLevel warn
+
+# SSL Engine Switch:
+# Enable/Disable SSL for this virtual host.
+SSLEngine on
+
+# SSL Protocol support:
+# List the enable protocol levels with which clients will be able to
+# connect. Disable SSLv2 access by default:
+SSLProtocol all -SSLv2
+
+# SSL Cipher Suite:
+# List the ciphers that the client is permitted to negotiate.
+# See the mod_ssl documentation for a complete list.
+SSLCipherSuite HIGH:MEDIUM:!aNULL:!MD5:!SEED:!IDEA
+
+# Speed-optimized SSL Cipher configuration:
+# If speed is your main concern (on busy HTTPS servers e.g.),
+# you might want to force clients to specific, performance
+# optimized ciphers. In this case, prepend those ciphers
+# to the SSLCipherSuite list, and enable SSLHonorCipherOrder.
+# Caveat: by giving precedence to RC4-SHA and AES128-SHA
+# (as in the example below), most connections will no longer
+# have perfect forward secrecy - if the server's key is
+# compromised, captures of past or future traffic must be
+# considered compromised, too.
+#SSLCipherSuite RC4-SHA:AES128-SHA:HIGH:MEDIUM:!aNULL:!MD5
+#SSLHonorCipherOrder on
+
+# Server Certificate:
+# Point SSLCertificateFile at a PEM encoded certificate. If
+# the certificate is encrypted, then you will be prompted for a
+# pass phrase. Note that a kill -HUP will prompt again. A new
+# certificate can be generated using the genkey(1) command.
+
+# Server Private Key:
+# If the key is not combined with the certificate, use this
+# directive to point at the key file. Keep in mind that if
+# you've both a RSA and a DSA private key you can configure
+# both in parallel (to also allow the use of DSA ciphers, etc.)
+
+# Server Certificate Chain:
+# Point SSLCertificateChainFile at a file containing the
+# concatenation of PEM encoded CA certificates which form the
+# certificate chain for the server certificate. Alternatively
+# the referenced file can be the same as SSLCertificateFile
+# when the CA certificates are directly appended to the server
+# certificate for convinience.
+#SSLCertificateChainFile /etc/pki/tls/certs/server-chain.crt
+
+# Certificate Authority (CA):
+# Set the CA certificate verification path where to find CA
+# certificates for client authentication or alternatively one
+# huge file containing all of them (file must be PEM encoded)
+#SSLCACertificateFile /etc/pki/tls/certs/ca-bundle.crt
+
+# Client Authentication (Type):
+# Client certificate verification type and depth. Types are
+# none, optional, require and optional_no_ca. Depth is a
+# number which specifies how deeply to verify the certificate
+# issuer chain before deciding the certificate is not valid.
+#SSLVerifyClient require
+#SSLVerifyDepth 10
+
+# Access Control:
+# With SSLRequire you can do per-directory access control based
+# on arbitrary complex boolean expressions containing server
+# variable checks and other lookup directives. The syntax is a
+# mixture between C and Perl. See the mod_ssl documentation
+# for more details.
+#
+#SSLRequire ( %{SSL_CIPHER} !~ m/^(EXP|NULL)/ \
+# and %{SSL_CLIENT_S_DN_O} eq "Snake Oil, Ltd." \
+# and %{SSL_CLIENT_S_DN_OU} in {"Staff", "CA", "Dev"} \
+# and %{TIME_WDAY} >= 1 and %{TIME_WDAY} <= 5 \
+# and %{TIME_HOUR} >= 8 and %{TIME_HOUR} <= 20 ) \
+# or %{REMOTE_ADDR} =~ m/^192\.76\.162\.[0-9]+$/
+#
+
+# SSL Engine Options:
+# Set various options for the SSL engine.
+# o FakeBasicAuth:
+# Translate the client X.509 into a Basic Authorisation. This means that
+# the standard Auth/DBMAuth methods can be used for access control. The
+# user name is the `one line' version of the client's X.509 certificate.
+# Note that no password is obtained from the user. Every entry in the user
+# file needs this password: `xxj31ZMTZzkVA'.
+# o ExportCertData:
+# This exports two additional environment variables: SSL_CLIENT_CERT and
+# SSL_SERVER_CERT. These contain the PEM-encoded certificates of the
+# server (always existing) and the client (only existing when client
+# authentication is used). This can be used to import the certificates
+# into CGI scripts.
+# o StdEnvVars:
+# This exports the standard SSL/TLS related `SSL_*' environment variables.
+# Per default this exportation is switched off for performance reasons,
+# because the extraction step is an expensive operation and is usually
+# useless for serving static content. So one usually enables the
+# exportation for CGI and SSI requests only.
+# o StrictRequire:
+# This denies access when "SSLRequireSSL" or "SSLRequire" applied even
+# under a "Satisfy any" situation, i.e. when it applies access is denied
+# and no other module can change it.
+# o OptRenegotiate:
+# This enables optimized SSL connection renegotiation handling when SSL
+# directives are used in per-directory context.
+#SSLOptions +FakeBasicAuth +ExportCertData +StrictRequire
+
+ SSLOptions +StdEnvVars
+
+
+ SSLOptions +StdEnvVars
+
+
+# SSL Protocol Adjustments:
+# The safe and default but still SSL/TLS standard compliant shutdown
+# approach is that mod_ssl sends the close notify alert but doesn't wait for
+# the close notify alert from client. When you need a different shutdown
+# approach you can use one of the following variables:
+# o ssl-unclean-shutdown:
+# This forces an unclean shutdown when the connection is closed, i.e. no
+# SSL close notify alert is send or allowed to received. This violates
+# the SSL/TLS standard but is needed for some brain-dead browsers. Use
+# this when you receive I/O errors because of the standard approach where
+# mod_ssl sends the close notify alert.
+# o ssl-accurate-shutdown:
+# This forces an accurate shutdown when the connection is closed, i.e. a
+# SSL close notify alert is send and mod_ssl waits for the close notify
+# alert of the client. This is 100% SSL/TLS standard compliant, but in
+# practice often causes hanging connections with brain-dead browsers. Use
+# this only for browsers where you know that their SSL implementation
+# works correctly.
+# Notice: Most problems of broken clients are also related to the HTTP
+# keep-alive facility, so you usually additionally want to disable
+# keep-alive for those clients, too. Use variable "nokeepalive" for this.
+# Similarly, one has to force some clients to use HTTP/1.0 to workaround
+# their broken HTTP/1.1 implementation. Use variables "downgrade-1.0" and
+# "force-response-1.0" for this.
+BrowserMatch "MSIE [2-5]" nokeepalive ssl-unclean-shutdown downgrade-1.0 force-response-1.0
+
+# Per-Server Logging:
+# The home of a custom SSL log file. Use this when you want a
+# compact non-error SSL logfile on a virtual host basis.
+CustomLog logs/ssl_request_log "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"
+
+
diff --git a/certbot-apache/certbot_apache/tests/testdata/centos7_apache/apache/httpd/conf.d/userdir.conf b/certbot-apache/certbot_apache/tests/testdata/centos7_apache/apache/httpd/conf.d/userdir.conf
new file mode 100644
index 000000000..b5d7a49ef
--- /dev/null
+++ b/certbot-apache/certbot_apache/tests/testdata/centos7_apache/apache/httpd/conf.d/userdir.conf
@@ -0,0 +1,36 @@
+#
+# UserDir: The name of the directory that is appended onto a user's home
+# directory if a ~user request is received.
+#
+# The path to the end user account 'public_html' directory must be
+# accessible to the webserver userid. This usually means that ~userid
+# must have permissions of 711, ~userid/public_html must have permissions
+# of 755, and documents contained therein must be world-readable.
+# Otherwise, the client will only receive a "403 Forbidden" message.
+#
+
+ #
+ # UserDir is disabled by default since it can confirm the presence
+ # of a username on the system (depending on home directory
+ # permissions).
+ #
+ UserDir disabled
+
+ #
+ # To enable requests to /~user/ to serve the user's public_html
+ # directory, remove the "UserDir disabled" line above, and uncomment
+ # the following line instead:
+ #
+ #UserDir public_html
+
+
+#
+# Control access to UserDir directories. The following is an example
+# for a site where these directories are restricted to read-only.
+#
+
+ AllowOverride FileInfo AuthConfig Limit Indexes
+ Options MultiViews Indexes SymLinksIfOwnerMatch IncludesNoExec
+ Require method GET POST OPTIONS
+
+
diff --git a/certbot-apache/certbot_apache/tests/testdata/centos7_apache/apache/httpd/conf.d/welcome.conf b/certbot-apache/certbot_apache/tests/testdata/centos7_apache/apache/httpd/conf.d/welcome.conf
new file mode 100644
index 000000000..c1b6c11d9
--- /dev/null
+++ b/certbot-apache/certbot_apache/tests/testdata/centos7_apache/apache/httpd/conf.d/welcome.conf
@@ -0,0 +1,22 @@
+#
+# This configuration file enables the default "Welcome" page if there
+# is no default index page present for the root URL. To disable the
+# Welcome page, comment out all the lines below.
+#
+# NOTE: if this file is removed, it will be restored on upgrades.
+#
+
+ Options -Indexes
+ ErrorDocument 403 /.noindex.html
+
+
+
+ AllowOverride None
+ Require all granted
+
+
+Alias /.noindex.html /usr/share/httpd/noindex/index.html
+Alias /noindex/css/bootstrap.min.css /usr/share/httpd/noindex/css/bootstrap.min.css
+Alias /noindex/css/open-sans.css /usr/share/httpd/noindex/css/open-sans.css
+Alias /images/apache_pb.gif /usr/share/httpd/noindex/images/apache_pb.gif
+Alias /images/poweredby.png /usr/share/httpd/noindex/images/poweredby.png
diff --git a/certbot-apache/certbot_apache/tests/testdata/centos7_apache/apache/httpd/conf.modules.d/00-base.conf b/certbot-apache/certbot_apache/tests/testdata/centos7_apache/apache/httpd/conf.modules.d/00-base.conf
new file mode 100644
index 000000000..31d979f20
--- /dev/null
+++ b/certbot-apache/certbot_apache/tests/testdata/centos7_apache/apache/httpd/conf.modules.d/00-base.conf
@@ -0,0 +1,77 @@
+#
+# This file loads most of the modules included with the Apache HTTP
+# Server itself.
+#
+
+LoadModule access_compat_module modules/mod_access_compat.so
+LoadModule actions_module modules/mod_actions.so
+LoadModule alias_module modules/mod_alias.so
+LoadModule allowmethods_module modules/mod_allowmethods.so
+LoadModule auth_basic_module modules/mod_auth_basic.so
+LoadModule auth_digest_module modules/mod_auth_digest.so
+LoadModule authn_anon_module modules/mod_authn_anon.so
+LoadModule authn_core_module modules/mod_authn_core.so
+LoadModule authn_dbd_module modules/mod_authn_dbd.so
+LoadModule authn_dbm_module modules/mod_authn_dbm.so
+LoadModule authn_file_module modules/mod_authn_file.so
+LoadModule authn_socache_module modules/mod_authn_socache.so
+LoadModule authz_core_module modules/mod_authz_core.so
+LoadModule authz_dbd_module modules/mod_authz_dbd.so
+LoadModule authz_dbm_module modules/mod_authz_dbm.so
+LoadModule authz_groupfile_module modules/mod_authz_groupfile.so
+LoadModule authz_host_module modules/mod_authz_host.so
+LoadModule authz_owner_module modules/mod_authz_owner.so
+LoadModule authz_user_module modules/mod_authz_user.so
+LoadModule autoindex_module modules/mod_autoindex.so
+LoadModule cache_module modules/mod_cache.so
+LoadModule cache_disk_module modules/mod_cache_disk.so
+LoadModule data_module modules/mod_data.so
+LoadModule dbd_module modules/mod_dbd.so
+LoadModule deflate_module modules/mod_deflate.so
+LoadModule dir_module modules/mod_dir.so
+LoadModule dumpio_module modules/mod_dumpio.so
+LoadModule echo_module modules/mod_echo.so
+LoadModule env_module modules/mod_env.so
+LoadModule expires_module modules/mod_expires.so
+LoadModule ext_filter_module modules/mod_ext_filter.so
+LoadModule filter_module modules/mod_filter.so
+LoadModule headers_module modules/mod_headers.so
+LoadModule include_module modules/mod_include.so
+LoadModule info_module modules/mod_info.so
+LoadModule log_config_module modules/mod_log_config.so
+LoadModule logio_module modules/mod_logio.so
+LoadModule mime_magic_module modules/mod_mime_magic.so
+LoadModule mime_module modules/mod_mime.so
+LoadModule negotiation_module modules/mod_negotiation.so
+LoadModule remoteip_module modules/mod_remoteip.so
+LoadModule reqtimeout_module modules/mod_reqtimeout.so
+LoadModule rewrite_module modules/mod_rewrite.so
+LoadModule setenvif_module modules/mod_setenvif.so
+LoadModule slotmem_plain_module modules/mod_slotmem_plain.so
+LoadModule slotmem_shm_module modules/mod_slotmem_shm.so
+LoadModule socache_dbm_module modules/mod_socache_dbm.so
+LoadModule socache_memcache_module modules/mod_socache_memcache.so
+LoadModule socache_shmcb_module modules/mod_socache_shmcb.so
+LoadModule status_module modules/mod_status.so
+LoadModule substitute_module modules/mod_substitute.so
+LoadModule suexec_module modules/mod_suexec.so
+LoadModule unique_id_module modules/mod_unique_id.so
+LoadModule unixd_module modules/mod_unixd.so
+LoadModule userdir_module modules/mod_userdir.so
+LoadModule version_module modules/mod_version.so
+LoadModule vhost_alias_module modules/mod_vhost_alias.so
+
+#LoadModule buffer_module modules/mod_buffer.so
+#LoadModule watchdog_module modules/mod_watchdog.so
+#LoadModule heartbeat_module modules/mod_heartbeat.so
+#LoadModule heartmonitor_module modules/mod_heartmonitor.so
+#LoadModule usertrack_module modules/mod_usertrack.so
+#LoadModule dialup_module modules/mod_dialup.so
+#LoadModule charset_lite_module modules/mod_charset_lite.so
+#LoadModule log_debug_module modules/mod_log_debug.so
+#LoadModule ratelimit_module modules/mod_ratelimit.so
+#LoadModule reflector_module modules/mod_reflector.so
+#LoadModule request_module modules/mod_request.so
+#LoadModule sed_module modules/mod_sed.so
+#LoadModule speling_module modules/mod_speling.so
+
diff --git a/certbot-apache/certbot_apache/tests/testdata/centos7_apache/apache/httpd/conf.modules.d/00-dav.conf b/certbot-apache/certbot_apache/tests/testdata/centos7_apache/apache/httpd/conf.modules.d/00-dav.conf
new file mode 100644
index 000000000..e6af8decd
--- /dev/null
+++ b/certbot-apache/certbot_apache/tests/testdata/centos7_apache/apache/httpd/conf.modules.d/00-dav.conf
@@ -0,0 +1,3 @@
+LoadModule dav_module modules/mod_dav.so
+LoadModule dav_fs_module modules/mod_dav_fs.so
+LoadModule dav_lock_module modules/mod_dav_lock.so
diff --git a/certbot-apache/certbot_apache/tests/testdata/centos7_apache/apache/httpd/conf.modules.d/00-lua.conf b/certbot-apache/certbot_apache/tests/testdata/centos7_apache/apache/httpd/conf.modules.d/00-lua.conf
new file mode 100644
index 000000000..9e0d0db6e
--- /dev/null
+++ b/certbot-apache/certbot_apache/tests/testdata/centos7_apache/apache/httpd/conf.modules.d/00-lua.conf
@@ -0,0 +1 @@
+LoadModule lua_module modules/mod_lua.so
diff --git a/certbot-apache/certbot_apache/tests/testdata/centos7_apache/apache/httpd/conf.modules.d/00-mpm.conf b/certbot-apache/certbot_apache/tests/testdata/centos7_apache/apache/httpd/conf.modules.d/00-mpm.conf
new file mode 100644
index 000000000..7bfd1d413
--- /dev/null
+++ b/certbot-apache/certbot_apache/tests/testdata/centos7_apache/apache/httpd/conf.modules.d/00-mpm.conf
@@ -0,0 +1,19 @@
+# Select the MPM module which should be used by uncommenting exactly
+# one of the following LoadModule lines:
+
+# prefork MPM: Implements a non-threaded, pre-forking web server
+# See: http://httpd.apache.org/docs/2.4/mod/prefork.html
+LoadModule mpm_prefork_module modules/mod_mpm_prefork.so
+
+# worker MPM: Multi-Processing Module implementing a hybrid
+# multi-threaded multi-process web server
+# See: http://httpd.apache.org/docs/2.4/mod/worker.html
+#
+#LoadModule mpm_worker_module modules/mod_mpm_worker.so
+
+# event MPM: A variant of the worker MPM with the goal of consuming
+# threads only for connections with active processing
+# See: http://httpd.apache.org/docs/2.4/mod/event.html
+#
+#LoadModule mpm_event_module modules/mod_mpm_event.so
+
diff --git a/certbot-apache/certbot_apache/tests/testdata/centos7_apache/apache/httpd/conf.modules.d/00-proxy.conf b/certbot-apache/certbot_apache/tests/testdata/centos7_apache/apache/httpd/conf.modules.d/00-proxy.conf
new file mode 100644
index 000000000..cc0bca077
--- /dev/null
+++ b/certbot-apache/certbot_apache/tests/testdata/centos7_apache/apache/httpd/conf.modules.d/00-proxy.conf
@@ -0,0 +1,16 @@
+# This file configures all the proxy modules:
+LoadModule proxy_module modules/mod_proxy.so
+LoadModule lbmethod_bybusyness_module modules/mod_lbmethod_bybusyness.so
+LoadModule lbmethod_byrequests_module modules/mod_lbmethod_byrequests.so
+LoadModule lbmethod_bytraffic_module modules/mod_lbmethod_bytraffic.so
+LoadModule lbmethod_heartbeat_module modules/mod_lbmethod_heartbeat.so
+LoadModule proxy_ajp_module modules/mod_proxy_ajp.so
+LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
+LoadModule proxy_connect_module modules/mod_proxy_connect.so
+LoadModule proxy_express_module modules/mod_proxy_express.so
+LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so
+LoadModule proxy_fdpass_module modules/mod_proxy_fdpass.so
+LoadModule proxy_ftp_module modules/mod_proxy_ftp.so
+LoadModule proxy_http_module modules/mod_proxy_http.so
+LoadModule proxy_scgi_module modules/mod_proxy_scgi.so
+LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so
diff --git a/certbot-apache/certbot_apache/tests/testdata/centos7_apache/apache/httpd/conf.modules.d/00-ssl.conf b/certbot-apache/certbot_apache/tests/testdata/centos7_apache/apache/httpd/conf.modules.d/00-ssl.conf
new file mode 100644
index 000000000..53235cd76
--- /dev/null
+++ b/certbot-apache/certbot_apache/tests/testdata/centos7_apache/apache/httpd/conf.modules.d/00-ssl.conf
@@ -0,0 +1 @@
+LoadModule ssl_module modules/mod_ssl.so
diff --git a/certbot-apache/certbot_apache/tests/testdata/centos7_apache/apache/httpd/conf.modules.d/00-systemd.conf b/certbot-apache/certbot_apache/tests/testdata/centos7_apache/apache/httpd/conf.modules.d/00-systemd.conf
new file mode 100644
index 000000000..b208c972d
--- /dev/null
+++ b/certbot-apache/certbot_apache/tests/testdata/centos7_apache/apache/httpd/conf.modules.d/00-systemd.conf
@@ -0,0 +1,2 @@
+# This file configures systemd module:
+LoadModule systemd_module modules/mod_systemd.so
diff --git a/certbot-apache/certbot_apache/tests/testdata/centos7_apache/apache/httpd/conf.modules.d/01-cgi.conf b/certbot-apache/certbot_apache/tests/testdata/centos7_apache/apache/httpd/conf.modules.d/01-cgi.conf
new file mode 100644
index 000000000..5b8b9362e
--- /dev/null
+++ b/certbot-apache/certbot_apache/tests/testdata/centos7_apache/apache/httpd/conf.modules.d/01-cgi.conf
@@ -0,0 +1,14 @@
+# This configuration file loads a CGI module appropriate to the MPM
+# which has been configured in 00-mpm.conf. mod_cgid should be used
+# with a threaded MPM; mod_cgi with the prefork MPM.
+
+
+ LoadModule cgid_module modules/mod_cgid.so
+
+
+ LoadModule cgid_module modules/mod_cgid.so
+
+
+ LoadModule cgi_module modules/mod_cgi.so
+
+
diff --git a/certbot-apache/certbot_apache/tests/testdata/centos7_apache/apache/httpd/conf/httpd.conf b/certbot-apache/certbot_apache/tests/testdata/centos7_apache/apache/httpd/conf/httpd.conf
new file mode 100644
index 000000000..a7af0dc1e
--- /dev/null
+++ b/certbot-apache/certbot_apache/tests/testdata/centos7_apache/apache/httpd/conf/httpd.conf
@@ -0,0 +1,353 @@
+#
+# This is the main Apache HTTP server configuration file. It contains the
+# configuration directives that give the server its instructions.
+# See for detailed information.
+# In particular, see
+#
+# for a discussion of each configuration directive.
+#
+# Do NOT simply read the instructions in here without understanding
+# what they do. They're here only as hints or reminders. If you are unsure
+# consult the online docs. You have been warned.
+#
+# Configuration and logfile names: If the filenames you specify for many
+# of the server's control files begin with "/" (or "drive:/" for Win32), the
+# server will use that explicit path. If the filenames do *not* begin
+# with "/", the value of ServerRoot is prepended -- so 'log/access_log'
+# with ServerRoot set to '/www' will be interpreted by the
+# server as '/www/log/access_log', where as '/log/access_log' will be
+# interpreted as '/log/access_log'.
+
+#
+# ServerRoot: The top of the directory tree under which the server's
+# configuration, error, and log files are kept.
+#
+# Do not add a slash at the end of the directory path. If you point
+# ServerRoot at a non-local disk, be sure to specify a local disk on the
+# Mutex directive, if file-based mutexes are used. If you wish to share the
+# same ServerRoot for multiple httpd daemons, you will need to change at
+# least PidFile.
+#
+ServerRoot "/etc/httpd"
+
+#
+# Listen: Allows you to bind Apache to specific IP addresses and/or
+# ports, instead of the default. See also the
+# directive.
+#
+# Change this to Listen on specific IP addresses as shown below to
+# prevent Apache from glomming onto all bound IP addresses.
+#
+#Listen 12.34.56.78:80
+Listen 80
+
+#
+# Dynamic Shared Object (DSO) Support
+#
+# To be able to use the functionality of a module which was built as a DSO you
+# have to place corresponding `LoadModule' lines at this location so the
+# directives contained in it are actually available _before_ they are used.
+# Statically compiled modules (those listed by `httpd -l') do not need
+# to be loaded here.
+#
+# Example:
+# LoadModule foo_module modules/mod_foo.so
+#
+Include conf.modules.d/*.conf
+
+#
+# If you wish httpd to run as a different user or group, you must run
+# httpd as root initially and it will switch.
+#
+# User/Group: The name (or #number) of the user/group to run httpd as.
+# It is usually good practice to create a dedicated user and group for
+# running httpd, as with most system services.
+#
+User apache
+Group apache
+
+# 'Main' server configuration
+#
+# The directives in this section set up the values used by the 'main'
+# server, which responds to any requests that aren't handled by a
+# definition. These values also provide defaults for
+# any containers you may define later in the file.
+#
+# All of these directives may appear inside containers,
+# in which case these default settings will be overridden for the
+# virtual host being defined.
+#
+
+#
+# ServerAdmin: Your address, where problems with the server should be
+# e-mailed. This address appears on some server-generated pages, such
+# as error documents. e.g. admin@your-domain.com
+#
+ServerAdmin root@localhost
+
+#
+# ServerName gives the name and port that the server uses to identify itself.
+# This can often be determined automatically, but we recommend you specify
+# it explicitly to prevent problems during startup.
+#
+# If your host doesn't have a registered DNS name, enter its IP address here.
+#
+#ServerName www.example.com:80
+
+#
+# Deny access to the entirety of your server's filesystem. You must
+# explicitly permit access to web content directories in other
+# blocks below.
+#
+
+ AllowOverride none
+ Require all denied
+
+
+#
+# Note that from this point forward you must specifically allow
+# particular features to be enabled - so if something's not working as
+# you might expect, make sure that you have specifically enabled it
+# below.
+#
+
+#
+# DocumentRoot: The directory out of which you will serve your
+# documents. By default, all requests are taken from this directory, but
+# symbolic links and aliases may be used to point to other locations.
+#
+DocumentRoot "/var/www/html"
+
+#
+# Relax access to content within /var/www.
+#
+
+ AllowOverride None
+ # Allow open access:
+ Require all granted
+
+
+# Further relax access to the default document root:
+
+ #
+ # Possible values for the Options directive are "None", "All",
+ # or any combination of:
+ # Indexes Includes FollowSymLinks SymLinksifOwnerMatch ExecCGI MultiViews
+ #
+ # Note that "MultiViews" must be named *explicitly* --- "Options All"
+ # doesn't give it to you.
+ #
+ # The Options directive is both complicated and important. Please see
+ # http://httpd.apache.org/docs/2.4/mod/core.html#options
+ # for more information.
+ #
+ Options Indexes FollowSymLinks
+
+ #
+ # AllowOverride controls what directives may be placed in .htaccess files.
+ # It can be "All", "None", or any combination of the keywords:
+ # Options FileInfo AuthConfig Limit
+ #
+ AllowOverride None
+
+ #
+ # Controls who can get stuff from this server.
+ #
+ Require all granted
+
+
+#
+# DirectoryIndex: sets the file that Apache will serve if a directory
+# is requested.
+#
+
+ DirectoryIndex index.html
+
+
+#
+# The following lines prevent .htaccess and .htpasswd files from being
+# viewed by Web clients.
+#
+
+ Require all denied
+
+
+#
+# ErrorLog: The location of the error log file.
+# If you do not specify an ErrorLog directive within a
+# container, error messages relating to that virtual host will be
+# logged here. If you *do* define an error logfile for a
+# container, that host's errors will be logged there and not here.
+#
+ErrorLog "logs/error_log"
+
+#
+# LogLevel: Control the number of messages logged to the error_log.
+# Possible values include: debug, info, notice, warn, error, crit,
+# alert, emerg.
+#
+LogLevel warn
+
+
+ #
+ # The following directives define some format nicknames for use with
+ # a CustomLog directive (see below).
+ #
+ LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
+ LogFormat "%h %l %u %t \"%r\" %>s %b" common
+
+
+ # You need to enable mod_logio.c to use %I and %O
+ LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio
+
+
+ #
+ # The location and format of the access logfile (Common Logfile Format).
+ # If you do not define any access logfiles within a
+ # container, they will be logged here. Contrariwise, if you *do*
+ # define per- access logfiles, transactions will be
+ # logged therein and *not* in this file.
+ #
+ #CustomLog "logs/access_log" common
+
+ #
+ # If you prefer a logfile with access, agent, and referer information
+ # (Combined Logfile Format) you can use the following directive.
+ #
+ CustomLog "logs/access_log" combined
+
+
+
+ #
+ # Redirect: Allows you to tell clients about documents that used to
+ # exist in your server's namespace, but do not anymore. The client
+ # will make a new request for the document at its new location.
+ # Example:
+ # Redirect permanent /foo http://www.example.com/bar
+
+ #
+ # Alias: Maps web paths into filesystem paths and is used to
+ # access content that does not live under the DocumentRoot.
+ # Example:
+ # Alias /webpath /full/filesystem/path
+ #
+ # If you include a trailing / on /webpath then the server will
+ # require it to be present in the URL. You will also likely
+ # need to provide a section to allow access to
+ # the filesystem path.
+
+ #
+ # ScriptAlias: This controls which directories contain server scripts.
+ # ScriptAliases are essentially the same as Aliases, except that
+ # documents in the target directory are treated as applications and
+ # run by the server when requested rather than as documents sent to the
+ # client. The same rules about trailing "/" apply to ScriptAlias
+ # directives as to Alias.
+ #
+ ScriptAlias /cgi-bin/ "/var/www/cgi-bin/"
+
+
+
+#
+# "/var/www/cgi-bin" should be changed to whatever your ScriptAliased
+# CGI directory exists, if you have that configured.
+#
+
+ AllowOverride None
+ Options None
+ Require all granted
+
+
+
+ #
+ # TypesConfig points to the file containing the list of mappings from
+ # filename extension to MIME-type.
+ #
+ TypesConfig /etc/mime.types
+
+ #
+ # AddType allows you to add to or override the MIME configuration
+ # file specified in TypesConfig for specific file types.
+ #
+ #AddType application/x-gzip .tgz
+ #
+ # AddEncoding allows you to have certain browsers uncompress
+ # information on the fly. Note: Not all browsers support this.
+ #
+ #AddEncoding x-compress .Z
+ #AddEncoding x-gzip .gz .tgz
+ #
+ # If the AddEncoding directives above are commented-out, then you
+ # probably should define those extensions to indicate media types:
+ #
+ AddType application/x-compress .Z
+ AddType application/x-gzip .gz .tgz
+
+ #
+ # AddHandler allows you to map certain file extensions to "handlers":
+ # actions unrelated to filetype. These can be either built into the server
+ # or added with the Action directive (see below)
+ #
+ # To use CGI scripts outside of ScriptAliased directories:
+ # (You will also need to add "ExecCGI" to the "Options" directive.)
+ #
+ #AddHandler cgi-script .cgi
+
+ # For type maps (negotiated resources):
+ #AddHandler type-map var
+
+ #
+ # Filters allow you to process content before it is sent to the client.
+ #
+ # To parse .shtml files for server-side includes (SSI):
+ # (You will also need to add "Includes" to the "Options" directive.)
+ #
+ AddType text/html .shtml
+ AddOutputFilter INCLUDES .shtml
+
+
+#
+# Specify a default charset for all content served; this enables
+# interpretation of all content as UTF-8 by default. To use the
+# default browser choice (ISO-8859-1), or to allow the META tags
+# in HTML content to override this choice, comment out this
+# directive:
+#
+AddDefaultCharset UTF-8
+
+
+ #
+ # The mod_mime_magic module allows the server to use various hints from the
+ # contents of the file itself to determine its type. The MIMEMagicFile
+ # directive tells the module where the hint definitions are located.
+ #
+ MIMEMagicFile conf/magic
+
+
+#
+# Customizable error responses come in three flavors:
+# 1) plain text 2) local redirects 3) external redirects
+#
+# Some examples:
+#ErrorDocument 500 "The server made a boo boo."
+#ErrorDocument 404 /missing.html
+#ErrorDocument 404 "/cgi-bin/missing_handler.pl"
+#ErrorDocument 402 http://www.example.com/subscription_info.html
+#
+
+#
+# EnableMMAP and EnableSendfile: On systems that support it,
+# memory-mapping or the sendfile syscall may be used to deliver
+# files. This usually improves server performance, but must
+# be turned off when serving from networked-mounted
+# filesystems or if support for these functions is otherwise
+# broken on your system.
+# Defaults if commented: EnableMMAP On, EnableSendfile Off
+#
+#EnableMMAP off
+EnableSendfile on
+
+# Supplemental configuration
+#
+# Load config files in the "/etc/httpd/conf.d" directory, if any.
+IncludeOptional conf.d/*.conf
diff --git a/certbot-apache/certbot_apache/tests/testdata/centos7_apache/apache/httpd/conf/magic b/certbot-apache/certbot_apache/tests/testdata/centos7_apache/apache/httpd/conf/magic
new file mode 100644
index 000000000..7c56119e9
--- /dev/null
+++ b/certbot-apache/certbot_apache/tests/testdata/centos7_apache/apache/httpd/conf/magic
@@ -0,0 +1,385 @@
+# Magic data for mod_mime_magic Apache module (originally for file(1) command)
+# The module is described in /manual/mod/mod_mime_magic.html
+#
+# The format is 4-5 columns:
+# Column #1: byte number to begin checking from, ">" indicates continuation
+# Column #2: type of data to match
+# Column #3: contents of data to match
+# Column #4: MIME type of result
+# Column #5: MIME encoding of result (optional)
+
+#------------------------------------------------------------------------------
+# Localstuff: file(1) magic for locally observed files
+# Add any locally observed files here.
+
+#------------------------------------------------------------------------------
+# end local stuff
+#------------------------------------------------------------------------------
+
+#------------------------------------------------------------------------------
+# Java
+
+0 short 0xcafe
+>2 short 0xbabe application/java
+
+#------------------------------------------------------------------------------
+# audio: file(1) magic for sound formats
+#
+# from Jan Nicolai Langfeldt ,
+#
+
+# Sun/NeXT audio data
+0 string .snd
+>12 belong 1 audio/basic
+>12 belong 2 audio/basic
+>12 belong 3 audio/basic
+>12 belong 4 audio/basic
+>12 belong 5 audio/basic
+>12 belong 6 audio/basic
+>12 belong 7 audio/basic
+
+>12 belong 23 audio/x-adpcm
+
+# DEC systems (e.g. DECstation 5000) use a variant of the Sun/NeXT format
+# that uses little-endian encoding and has a different magic number
+# (0x0064732E in little-endian encoding).
+0 lelong 0x0064732E
+>12 lelong 1 audio/x-dec-basic
+>12 lelong 2 audio/x-dec-basic
+>12 lelong 3 audio/x-dec-basic
+>12 lelong 4 audio/x-dec-basic
+>12 lelong 5 audio/x-dec-basic
+>12 lelong 6 audio/x-dec-basic
+>12 lelong 7 audio/x-dec-basic
+# compressed (G.721 ADPCM)
+>12 lelong 23 audio/x-dec-adpcm
+
+# Bytes 0-3 of AIFF, AIFF-C, & 8SVX audio files are "FORM"
+# AIFF audio data
+8 string AIFF audio/x-aiff
+# AIFF-C audio data
+8 string AIFC audio/x-aiff
+# IFF/8SVX audio data
+8 string 8SVX audio/x-aiff
+
+# Creative Labs AUDIO stuff
+# Standard MIDI data
+0 string MThd audio/unknown
+#>9 byte >0 (format %d)
+#>11 byte >1 using %d channels
+# Creative Music (CMF) data
+0 string CTMF audio/unknown
+# SoundBlaster instrument data
+0 string SBI audio/unknown
+# Creative Labs voice data
+0 string Creative\ Voice\ File audio/unknown
+## is this next line right? it came this way...
+#>19 byte 0x1A
+#>23 byte >0 - version %d
+#>22 byte >0 \b.%d
+
+# [GRR 950115: is this also Creative Labs? Guessing that first line
+# should be string instead of unknown-endian long...]
+#0 long 0x4e54524b MultiTrack sound data
+#0 string NTRK MultiTrack sound data
+#>4 long x - version %ld
+
+# Microsoft WAVE format (*.wav)
+# [GRR 950115: probably all of the shorts and longs should be leshort/lelong]
+# Microsoft RIFF
+0 string RIFF audio/unknown
+# - WAVE format
+>8 string WAVE audio/x-wav
+# MPEG audio.
+0 beshort&0xfff0 0xfff0 audio/mpeg
+# C64 SID Music files, from Linus Walleij
+0 string PSID audio/prs.sid
+
+#------------------------------------------------------------------------------
+# c-lang: file(1) magic for C programs or various scripts
+#
+
+# XPM icons (Greg Roelofs, newt@uchicago.edu)
+# ideally should go into "images", but entries below would tag XPM as C source
+0 string /*\ XPM image/x-xbm 7bit
+
+# this first will upset you if you're a PL/1 shop... (are there any left?)
+# in which case rm it; ascmagic will catch real C programs
+# C or REXX program text
+0 string /* text/plain
+# C++ program text
+0 string // text/plain
+
+#------------------------------------------------------------------------------
+# compress: file(1) magic for pure-compression formats (no archives)
+#
+# compress, gzip, pack, compact, huf, squeeze, crunch, freeze, yabba, whap, etc.
+#
+# Formats for various forms of compressed data
+# Formats for "compress" proper have been moved into "compress.c",
+# because it tries to uncompress it to figure out what's inside.
+
+# standard unix compress
+0 string \037\235 application/octet-stream x-compress
+
+# gzip (GNU zip, not to be confused with [Info-ZIP/PKWARE] zip archiver)
+0 string \037\213 application/octet-stream x-gzip
+
+# According to gzip.h, this is the correct byte order for packed data.
+0 string \037\036 application/octet-stream
+#
+# This magic number is byte-order-independent.
+#
+0 short 017437 application/octet-stream
+
+# XXX - why *two* entries for "compacted data", one of which is
+# byte-order independent, and one of which is byte-order dependent?
+#
+# compacted data
+0 short 0x1fff application/octet-stream
+0 string \377\037 application/octet-stream
+# huf output
+0 short 0145405 application/octet-stream
+
+# Squeeze and Crunch...
+# These numbers were gleaned from the Unix versions of the programs to
+# handle these formats. Note that I can only uncrunch, not crunch, and
+# I didn't have a crunched file handy, so the crunch number is untested.
+# Keith Waclena
+#0 leshort 0x76FF squeezed data (CP/M, DOS)
+#0 leshort 0x76FE crunched data (CP/M, DOS)
+
+# Freeze
+#0 string \037\237 Frozen file 2.1
+#0 string \037\236 Frozen file 1.0 (or gzip 0.5)
+
+# lzh?
+#0 string \037\240 LZH compressed data
+
+#------------------------------------------------------------------------------
+# frame: file(1) magic for FrameMaker files
+#
+# This stuff came on a FrameMaker demo tape, most of which is
+# copyright, but this file is "published" as witness the following:
+#
+0 string \
+# and Anna Shergold
+#
+0 string \
+0 string \14 byte 12 (OS/2 1.x format)
+#>14 byte 64 (OS/2 2.x format)
+#>14 byte 40 (Windows 3.x format)
+#0 string IC icon
+#0 string PI pointer
+#0 string CI color icon
+#0 string CP color pointer
+#0 string BA bitmap array
+
+0 string \x89PNG image/png
+0 string FWS application/x-shockwave-flash
+0 string CWS application/x-shockwave-flash
+
+#------------------------------------------------------------------------------
+# lisp: file(1) magic for lisp programs
+#
+# various lisp types, from Daniel Quinlan (quinlan@yggdrasil.com)
+0 string ;; text/plain 8bit
+# Emacs 18 - this is always correct, but not very magical.
+0 string \012( application/x-elc
+# Emacs 19
+0 string ;ELC\023\000\000\000 application/x-elc
+
+#------------------------------------------------------------------------------
+# mail.news: file(1) magic for mail and news
+#
+# There are tests to ascmagic.c to cope with mail and news.
+0 string Relay-Version: message/rfc822 7bit
+0 string #!\ rnews message/rfc822 7bit
+0 string N#!\ rnews message/rfc822 7bit
+0 string Forward\ to message/rfc822 7bit
+0 string Pipe\ to message/rfc822 7bit
+0 string Return-Path: message/rfc822 7bit
+0 string Path: message/news 8bit
+0 string Xref: message/news 8bit
+0 string From: message/rfc822 7bit
+0 string Article message/news 8bit
+#------------------------------------------------------------------------------
+# msword: file(1) magic for MS Word files
+#
+# Contributor claims:
+# Reversed-engineered MS Word magic numbers
+#
+
+0 string \376\067\0\043 application/msword
+0 string \333\245-\0\0\0 application/msword
+
+# disable this one because it applies also to other
+# Office/OLE documents for which msword is not correct. See PR#2608.
+#0 string \320\317\021\340\241\261 application/msword
+
+
+
+#------------------------------------------------------------------------------
+# printer: file(1) magic for printer-formatted files
+#
+
+# PostScript
+0 string %! application/postscript
+0 string \004%! application/postscript
+
+# Acrobat
+# (due to clamen@cs.cmu.edu)
+0 string %PDF- application/pdf
+
+#------------------------------------------------------------------------------
+# sc: file(1) magic for "sc" spreadsheet
+#
+38 string Spreadsheet application/x-sc
+
+#------------------------------------------------------------------------------
+# tex: file(1) magic for TeX files
+#
+# XXX - needs byte-endian stuff (big-endian and little-endian DVI?)
+#
+# From
+
+# Although we may know the offset of certain text fields in TeX DVI
+# and font files, we can't use them reliably because they are not
+# zero terminated. [but we do anyway, christos]
+0 string \367\002 application/x-dvi
+#0 string \367\203 TeX generic font data
+#0 string \367\131 TeX packed font data
+#0 string \367\312 TeX virtual font data
+#0 string This\ is\ TeX, TeX transcript text
+#0 string This\ is\ METAFONT, METAFONT transcript text
+
+# There is no way to detect TeX Font Metric (*.tfm) files without
+# breaking them apart and reading the data. The following patterns
+# match most *.tfm files generated by METAFONT or afm2tfm.
+#2 string \000\021 TeX font metric data
+#2 string \000\022 TeX font metric data
+#>34 string >\0 (%s)
+
+# Texinfo and GNU Info, from Daniel Quinlan (quinlan@yggdrasil.com)
+#0 string \\input\ texinfo Texinfo source text
+#0 string This\ is\ Info\ file GNU Info text
+
+# correct TeX magic for Linux (and maybe more)
+# from Peter Tobias (tobias@server.et-inf.fho-emden.de)
+#
+0 leshort 0x02f7 application/x-dvi
+
+# RTF - Rich Text Format
+0 string {\\rtf application/rtf
+
+#------------------------------------------------------------------------------
+# animation: file(1) magic for animation/movie formats
+#
+# animation formats, originally from vax@ccwf.cc.utexas.edu (VaX#n8)
+# MPEG file
+0 string \000\000\001\263 video/mpeg
+#
+# The contributor claims:
+# I couldn't find a real magic number for these, however, this
+# -appears- to work. Note that it might catch other files, too,
+# so BE CAREFUL!
+#
+# Note that title and author appear in the two 20-byte chunks
+# at decimal offsets 2 and 22, respectively, but they are XOR'ed with
+# 255 (hex FF)! DL format SUCKS BIG ROCKS.
+#
+# DL file version 1 , medium format (160x100, 4 images/screen)
+0 byte 1 video/unknown
+0 byte 2 video/unknown
+# Quicktime video, from Linus Walleij
+# from Apple quicktime file format documentation.
+4 string moov video/quicktime
+4 string mdat video/quicktime
+
diff --git a/certbot-apache/certbot_apache/tests/testdata/centos7_apache/apache/sites b/certbot-apache/certbot_apache/tests/testdata/centos7_apache/apache/sites
new file mode 100644
index 000000000..6af1f63fa
--- /dev/null
+++ b/certbot-apache/certbot_apache/tests/testdata/centos7_apache/apache/sites
@@ -0,0 +1 @@
+conf.d/centos.example.com.conf, centos.example.com
diff --git a/certbot-apache/certbot_apache/tests/testdata/centos7_apache/apache/sysconfig/httpd b/certbot-apache/certbot_apache/tests/testdata/centos7_apache/apache/sysconfig/httpd
new file mode 100644
index 000000000..0bf6b176c
--- /dev/null
+++ b/certbot-apache/certbot_apache/tests/testdata/centos7_apache/apache/sysconfig/httpd
@@ -0,0 +1,25 @@
+#
+# This file can be used to set additional environment variables for
+# the httpd process, or pass additional options to the httpd
+# executable.
+#
+# Note: With previous versions of httpd, the MPM could be changed by
+# editing an "HTTPD" variable here. With the current version, that
+# variable is now ignored. The MPM is a loadable module, and the
+# choice of MPM can be changed by editing the configuration file
+# /etc/httpd/conf.modules.d/00-mpm.conf.
+#
+
+#
+# To pass additional options (for instance, -D definitions) to the
+# httpd binary at startup, set OPTIONS here.
+#
+OPTIONS="-D mock_define -D mock_define_too -D mock_value=TRUE"
+
+#
+# This setting ensures the httpd process is started in the "C" locale
+# by default. (Some modules will not behave correctly if
+# case-sensitive string comparisons are performed in a different
+# locale.)
+#
+LANG=C
diff --git a/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/httpd.conf b/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/httpd.conf
new file mode 100644
index 000000000..e5693ffff
--- /dev/null
+++ b/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/httpd.conf
@@ -0,0 +1,157 @@
+# This is a modification of the default Apache 2.4 configuration file
+# for Gentoo Linux.
+#
+# Support:
+# http://www.gentoo.org/main/en/lists.xml [mailing lists]
+# http://forums.gentoo.org/ [web forums]
+# irc://irc.freenode.net#gentoo-apache [irc chat]
+#
+# Bug Reports:
+# http://bugs.gentoo.org [gentoo related bugs]
+# http://httpd.apache.org/bug_report.html [apache httpd related bugs]
+#
+#
+# This is the main Apache HTTP server configuration file. It contains the
+# configuration directives that give the server its instructions.
+# See for detailed information.
+# In particular, see
+#
+# for a discussion of each configuration directive.
+#
+# Do NOT simply read the instructions in here without understanding
+# what they do. They're here only as hints or reminders. If you are unsure
+# consult the online docs. You have been warned.
+#
+# Configuration and logfile names: If the filenames you specify for many
+# of the server's control files begin with "/" (or "drive:/" for Win32), the
+# server will use that explicit path. If the filenames do *not* begin
+# with "/", the value of ServerRoot is prepended -- so "var/log/apache2/foo_log"
+# with ServerRoot set to "/usr" will be interpreted by the
+# server as "/usr/var/log/apache2/foo.log".
+
+# ServerRoot: The top of the directory tree under which the server's
+# configuration, error, and log files are kept.
+#
+# Do not add a slash at the end of the directory path. If you point
+# ServerRoot at a non-local disk, be sure to point the LockFile directive
+# at a local disk. If you wish to share the same ServerRoot for multiple
+# httpd daemons, you will need to change at least LockFile and PidFile.
+# Comment: The LockFile directive has been replaced by the Mutex directive
+ServerRoot "/usr/lib64/apache2"
+
+# Dynamic Shared Object (DSO) Support
+#
+# To be able to use the functionality of a module which was built as a DSO you
+# have to place corresponding `LoadModule' lines at this location so the
+# directives contained in it are actually available _before_ they are used.
+# Statically compiled modules (those listed by `httpd -l') do not need
+# to be loaded here.
+#
+# Example:
+# LoadModule foo_module modules/mod_foo.so
+#
+# GENTOO: Automatically defined based on APACHE2_MODULES USE_EXPAND variable.
+# Do not change manually, it will be overwritten on upgrade.
+#
+# The following modules are considered as the default configuration.
+# If you wish to disable one of them, you may have to alter other
+# configuration directives.
+#
+# Change these at your own risk!
+
+LoadModule actions_module modules/mod_actions.so
+LoadModule alias_module modules/mod_alias.so
+LoadModule auth_basic_module modules/mod_auth_basic.so
+LoadModule authn_anon_module modules/mod_authn_anon.so
+LoadModule authn_core_module modules/mod_authn_core.so
+LoadModule authn_dbm_module modules/mod_authn_dbm.so
+LoadModule authn_file_module modules/mod_authn_file.so
+LoadModule authz_core_module modules/mod_authz_core.so
+LoadModule authz_dbm_module modules/mod_authz_dbm.so
+LoadModule authz_groupfile_module modules/mod_authz_groupfile.so
+LoadModule authz_host_module modules/mod_authz_host.so
+LoadModule authz_owner_module modules/mod_authz_owner.so
+LoadModule authz_user_module modules/mod_authz_user.so
+LoadModule autoindex_module modules/mod_autoindex.so
+
+LoadModule cache_module modules/mod_cache.so
+
+LoadModule cgi_module modules/mod_cgi.so
+LoadModule cgid_module modules/mod_cgid.so
+
+LoadModule dav_module modules/mod_dav.so
+
+
+LoadModule dav_fs_module modules/mod_dav_fs.so
+
+
+LoadModule dav_lock_module modules/mod_dav_lock.so
+
+LoadModule deflate_module modules/mod_deflate.so
+LoadModule dir_module modules/mod_dir.so
+LoadModule env_module modules/mod_env.so
+LoadModule expires_module modules/mod_expires.so
+LoadModule ext_filter_module modules/mod_ext_filter.so
+
+LoadModule file_cache_module modules/mod_file_cache.so
+
+LoadModule filter_module modules/mod_filter.so
+LoadModule headers_module modules/mod_headers.so
+LoadModule include_module modules/mod_include.so
+
+LoadModule info_module modules/mod_info.so
+
+LoadModule log_config_module modules/mod_log_config.so
+LoadModule logio_module modules/mod_logio.so
+LoadModule mime_module modules/mod_mime.so
+LoadModule mime_magic_module modules/mod_mime_magic.so
+LoadModule negotiation_module modules/mod_negotiation.so
+LoadModule rewrite_module modules/mod_rewrite.so
+LoadModule setenvif_module modules/mod_setenvif.so
+
+LoadModule socache_shmcb_module modules/mod_socache_shmcb.so
+
+LoadModule speling_module modules/mod_speling.so
+
+LoadModule ssl_module modules/mod_ssl.so
+
+
+LoadModule status_module modules/mod_status.so
+
+LoadModule unique_id_module modules/mod_unique_id.so
+LoadModule unixd_module modules/mod_unixd.so
+
+LoadModule userdir_module modules/mod_userdir.so
+
+LoadModule usertrack_module modules/mod_usertrack.so
+LoadModule vhost_alias_module modules/mod_vhost_alias.so
+
+# If you wish httpd to run as a different user or group, you must run
+# httpd as root initially and it will switch.
+#
+# User/Group: The name (or #number) of the user/group to run httpd as.
+# It is usually good practice to create a dedicated user and group for
+# running httpd, as with most system services.
+User apache
+Group apache
+
+# Supplemental configuration
+#
+# Most of the configuration files in the /etc/apache2/modules.d/ directory can
+# be turned on using APACHE2_OPTS in /etc/conf.d/apache2 to add extra features
+# or to modify the default configuration of the server.
+#
+# To know which flag to add to APACHE2_OPTS, look at the first line of the
+# the file, which will usually be an where OPTION is the
+# flag to use.
+
+Include modules.d/*.conf
+
+# Virtual-host support
+#
+# Gentoo has made using virtual-hosts easy. In /etc/apache2/vhosts.d/ we
+# include a default vhost (enabled by adding -D DEFAULT_VHOST to
+# APACHE2_OPTS in /etc/conf.d/apache2).
+Include vhosts.d/*.conf
+
+# vim: ts=4 filetype=apache
diff --git a/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/magic b/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/magic
new file mode 100644
index 000000000..7c56119e9
--- /dev/null
+++ b/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/magic
@@ -0,0 +1,385 @@
+# Magic data for mod_mime_magic Apache module (originally for file(1) command)
+# The module is described in /manual/mod/mod_mime_magic.html
+#
+# The format is 4-5 columns:
+# Column #1: byte number to begin checking from, ">" indicates continuation
+# Column #2: type of data to match
+# Column #3: contents of data to match
+# Column #4: MIME type of result
+# Column #5: MIME encoding of result (optional)
+
+#------------------------------------------------------------------------------
+# Localstuff: file(1) magic for locally observed files
+# Add any locally observed files here.
+
+#------------------------------------------------------------------------------
+# end local stuff
+#------------------------------------------------------------------------------
+
+#------------------------------------------------------------------------------
+# Java
+
+0 short 0xcafe
+>2 short 0xbabe application/java
+
+#------------------------------------------------------------------------------
+# audio: file(1) magic for sound formats
+#
+# from Jan Nicolai Langfeldt ,
+#
+
+# Sun/NeXT audio data
+0 string .snd
+>12 belong 1 audio/basic
+>12 belong 2 audio/basic
+>12 belong 3 audio/basic
+>12 belong 4 audio/basic
+>12 belong 5 audio/basic
+>12 belong 6 audio/basic
+>12 belong 7 audio/basic
+
+>12 belong 23 audio/x-adpcm
+
+# DEC systems (e.g. DECstation 5000) use a variant of the Sun/NeXT format
+# that uses little-endian encoding and has a different magic number
+# (0x0064732E in little-endian encoding).
+0 lelong 0x0064732E
+>12 lelong 1 audio/x-dec-basic
+>12 lelong 2 audio/x-dec-basic
+>12 lelong 3 audio/x-dec-basic
+>12 lelong 4 audio/x-dec-basic
+>12 lelong 5 audio/x-dec-basic
+>12 lelong 6 audio/x-dec-basic
+>12 lelong 7 audio/x-dec-basic
+# compressed (G.721 ADPCM)
+>12 lelong 23 audio/x-dec-adpcm
+
+# Bytes 0-3 of AIFF, AIFF-C, & 8SVX audio files are "FORM"
+# AIFF audio data
+8 string AIFF audio/x-aiff
+# AIFF-C audio data
+8 string AIFC audio/x-aiff
+# IFF/8SVX audio data
+8 string 8SVX audio/x-aiff
+
+# Creative Labs AUDIO stuff
+# Standard MIDI data
+0 string MThd audio/unknown
+#>9 byte >0 (format %d)
+#>11 byte >1 using %d channels
+# Creative Music (CMF) data
+0 string CTMF audio/unknown
+# SoundBlaster instrument data
+0 string SBI audio/unknown
+# Creative Labs voice data
+0 string Creative\ Voice\ File audio/unknown
+## is this next line right? it came this way...
+#>19 byte 0x1A
+#>23 byte >0 - version %d
+#>22 byte >0 \b.%d
+
+# [GRR 950115: is this also Creative Labs? Guessing that first line
+# should be string instead of unknown-endian long...]
+#0 long 0x4e54524b MultiTrack sound data
+#0 string NTRK MultiTrack sound data
+#>4 long x - version %ld
+
+# Microsoft WAVE format (*.wav)
+# [GRR 950115: probably all of the shorts and longs should be leshort/lelong]
+# Microsoft RIFF
+0 string RIFF audio/unknown
+# - WAVE format
+>8 string WAVE audio/x-wav
+# MPEG audio.
+0 beshort&0xfff0 0xfff0 audio/mpeg
+# C64 SID Music files, from Linus Walleij
+0 string PSID audio/prs.sid
+
+#------------------------------------------------------------------------------
+# c-lang: file(1) magic for C programs or various scripts
+#
+
+# XPM icons (Greg Roelofs, newt@uchicago.edu)
+# ideally should go into "images", but entries below would tag XPM as C source
+0 string /*\ XPM image/x-xbm 7bit
+
+# this first will upset you if you're a PL/1 shop... (are there any left?)
+# in which case rm it; ascmagic will catch real C programs
+# C or REXX program text
+0 string /* text/plain
+# C++ program text
+0 string // text/plain
+
+#------------------------------------------------------------------------------
+# compress: file(1) magic for pure-compression formats (no archives)
+#
+# compress, gzip, pack, compact, huf, squeeze, crunch, freeze, yabba, whap, etc.
+#
+# Formats for various forms of compressed data
+# Formats for "compress" proper have been moved into "compress.c",
+# because it tries to uncompress it to figure out what's inside.
+
+# standard unix compress
+0 string \037\235 application/octet-stream x-compress
+
+# gzip (GNU zip, not to be confused with [Info-ZIP/PKWARE] zip archiver)
+0 string \037\213 application/octet-stream x-gzip
+
+# According to gzip.h, this is the correct byte order for packed data.
+0 string \037\036 application/octet-stream
+#
+# This magic number is byte-order-independent.
+#
+0 short 017437 application/octet-stream
+
+# XXX - why *two* entries for "compacted data", one of which is
+# byte-order independent, and one of which is byte-order dependent?
+#
+# compacted data
+0 short 0x1fff application/octet-stream
+0 string \377\037 application/octet-stream
+# huf output
+0 short 0145405 application/octet-stream
+
+# Squeeze and Crunch...
+# These numbers were gleaned from the Unix versions of the programs to
+# handle these formats. Note that I can only uncrunch, not crunch, and
+# I didn't have a crunched file handy, so the crunch number is untested.
+# Keith Waclena
+#0 leshort 0x76FF squeezed data (CP/M, DOS)
+#0 leshort 0x76FE crunched data (CP/M, DOS)
+
+# Freeze
+#0 string \037\237 Frozen file 2.1
+#0 string \037\236 Frozen file 1.0 (or gzip 0.5)
+
+# lzh?
+#0 string \037\240 LZH compressed data
+
+#------------------------------------------------------------------------------
+# frame: file(1) magic for FrameMaker files
+#
+# This stuff came on a FrameMaker demo tape, most of which is
+# copyright, but this file is "published" as witness the following:
+#
+0 string \
+# and Anna Shergold
+#
+0 string \
+0 string \14 byte 12 (OS/2 1.x format)
+#>14 byte 64 (OS/2 2.x format)
+#>14 byte 40 (Windows 3.x format)
+#0 string IC icon
+#0 string PI pointer
+#0 string CI color icon
+#0 string CP color pointer
+#0 string BA bitmap array
+
+0 string \x89PNG image/png
+0 string FWS application/x-shockwave-flash
+0 string CWS application/x-shockwave-flash
+
+#------------------------------------------------------------------------------
+# lisp: file(1) magic for lisp programs
+#
+# various lisp types, from Daniel Quinlan (quinlan@yggdrasil.com)
+0 string ;; text/plain 8bit
+# Emacs 18 - this is always correct, but not very magical.
+0 string \012( application/x-elc
+# Emacs 19
+0 string ;ELC\023\000\000\000 application/x-elc
+
+#------------------------------------------------------------------------------
+# mail.news: file(1) magic for mail and news
+#
+# There are tests to ascmagic.c to cope with mail and news.
+0 string Relay-Version: message/rfc822 7bit
+0 string #!\ rnews message/rfc822 7bit
+0 string N#!\ rnews message/rfc822 7bit
+0 string Forward\ to message/rfc822 7bit
+0 string Pipe\ to message/rfc822 7bit
+0 string Return-Path: message/rfc822 7bit
+0 string Path: message/news 8bit
+0 string Xref: message/news 8bit
+0 string From: message/rfc822 7bit
+0 string Article message/news 8bit
+#------------------------------------------------------------------------------
+# msword: file(1) magic for MS Word files
+#
+# Contributor claims:
+# Reversed-engineered MS Word magic numbers
+#
+
+0 string \376\067\0\043 application/msword
+0 string \333\245-\0\0\0 application/msword
+
+# disable this one because it applies also to other
+# Office/OLE documents for which msword is not correct. See PR#2608.
+#0 string \320\317\021\340\241\261 application/msword
+
+
+
+#------------------------------------------------------------------------------
+# printer: file(1) magic for printer-formatted files
+#
+
+# PostScript
+0 string %! application/postscript
+0 string \004%! application/postscript
+
+# Acrobat
+# (due to clamen@cs.cmu.edu)
+0 string %PDF- application/pdf
+
+#------------------------------------------------------------------------------
+# sc: file(1) magic for "sc" spreadsheet
+#
+38 string Spreadsheet application/x-sc
+
+#------------------------------------------------------------------------------
+# tex: file(1) magic for TeX files
+#
+# XXX - needs byte-endian stuff (big-endian and little-endian DVI?)
+#
+# From
+
+# Although we may know the offset of certain text fields in TeX DVI
+# and font files, we can't use them reliably because they are not
+# zero terminated. [but we do anyway, christos]
+0 string \367\002 application/x-dvi
+#0 string \367\203 TeX generic font data
+#0 string \367\131 TeX packed font data
+#0 string \367\312 TeX virtual font data
+#0 string This\ is\ TeX, TeX transcript text
+#0 string This\ is\ METAFONT, METAFONT transcript text
+
+# There is no way to detect TeX Font Metric (*.tfm) files without
+# breaking them apart and reading the data. The following patterns
+# match most *.tfm files generated by METAFONT or afm2tfm.
+#2 string \000\021 TeX font metric data
+#2 string \000\022 TeX font metric data
+#>34 string >\0 (%s)
+
+# Texinfo and GNU Info, from Daniel Quinlan (quinlan@yggdrasil.com)
+#0 string \\input\ texinfo Texinfo source text
+#0 string This\ is\ Info\ file GNU Info text
+
+# correct TeX magic for Linux (and maybe more)
+# from Peter Tobias (tobias@server.et-inf.fho-emden.de)
+#
+0 leshort 0x02f7 application/x-dvi
+
+# RTF - Rich Text Format
+0 string {\\rtf application/rtf
+
+#------------------------------------------------------------------------------
+# animation: file(1) magic for animation/movie formats
+#
+# animation formats, originally from vax@ccwf.cc.utexas.edu (VaX#n8)
+# MPEG file
+0 string \000\000\001\263 video/mpeg
+#
+# The contributor claims:
+# I couldn't find a real magic number for these, however, this
+# -appears- to work. Note that it might catch other files, too,
+# so BE CAREFUL!
+#
+# Note that title and author appear in the two 20-byte chunks
+# at decimal offsets 2 and 22, respectively, but they are XOR'ed with
+# 255 (hex FF)! DL format SUCKS BIG ROCKS.
+#
+# DL file version 1 , medium format (160x100, 4 images/screen)
+0 byte 1 video/unknown
+0 byte 2 video/unknown
+# Quicktime video, from Linus Walleij
+# from Apple quicktime file format documentation.
+4 string moov video/quicktime
+4 string mdat video/quicktime
+
diff --git a/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/modules.d/.keep_www-servers_apache-2 b/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/modules.d/.keep_www-servers_apache-2
new file mode 100644
index 000000000..e69de29bb
diff --git a/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/modules.d/00_default_settings.conf b/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/modules.d/00_default_settings.conf
new file mode 100644
index 000000000..38635aa9d
--- /dev/null
+++ b/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/modules.d/00_default_settings.conf
@@ -0,0 +1,131 @@
+# This configuration file reflects default settings for Apache HTTP Server.
+# You may change these, but chances are that you may not need to.
+
+# Timeout: The number of seconds before receives and sends time out.
+Timeout 300
+
+# KeepAlive: Whether or not to allow persistent connections (more than
+# one request per connection). Set to "Off" to deactivate.
+KeepAlive On
+
+# MaxKeepAliveRequests: The maximum number of requests to allow
+# during a persistent connection. Set to 0 to allow an unlimited amount.
+# We recommend you leave this number high, for maximum performance.
+MaxKeepAliveRequests 100
+
+# KeepAliveTimeout: Number of seconds to wait for the next request from the
+# same client on the same connection.
+KeepAliveTimeout 15
+
+# UseCanonicalName: Determines how Apache constructs self-referencing
+# URLs and the SERVER_NAME and SERVER_PORT variables.
+# When set "Off", Apache will use the Hostname and Port supplied
+# by the client. When set "On", Apache will use the value of the
+# ServerName directive.
+UseCanonicalName Off
+
+# AccessFileName: The name of the file to look for in each directory
+# for additional configuration directives. See also the AllowOverride
+# directive.
+AccessFileName .htaccess
+
+# ServerTokens
+# This directive configures what you return as the Server HTTP response
+# Header. The default is 'Full' which sends information about the OS-Type
+# and compiled in modules.
+# Set to one of: Full | OS | Minor | Minimal | Major | Prod
+# where Full conveys the most information, and Prod the least.
+ServerTokens Prod
+
+# TraceEnable
+# This directive overrides the behavior of TRACE for both the core server and
+# mod_proxy. The default TraceEnable on permits TRACE requests per RFC 2616,
+# which disallows any request body to accompany the request. TraceEnable off
+# causes the core server and mod_proxy to return a 405 (Method not allowed)
+# error to the client.
+# For security reasons this is turned off by default. (bug #240680)
+TraceEnable off
+
+# Optionally add a line containing the server version and virtual host
+# name to server-generated pages (internal error documents, FTP directory
+# listings, mod_status and mod_info output etc., but not CGI generated
+# documents or custom error documents).
+# Set to "EMail" to also include a mailto: link to the ServerAdmin.
+# Set to one of: On | Off | EMail
+ServerSignature On
+
+# HostnameLookups: Log the names of clients or just their IP addresses
+# e.g., www.apache.org (on) or 204.62.129.132 (off).
+# The default is off because it'd be overall better for the net if people
+# had to knowingly turn this feature on, since enabling it means that
+# each client request will result in AT LEAST one lookup request to the
+# nameserver.
+HostnameLookups Off
+
+# EnableMMAP and EnableSendfile: On systems that support it,
+# memory-mapping or the sendfile syscall is used to deliver
+# files. This usually improves server performance, but must
+# be turned off when serving from networked-mounted
+# filesystems or if support for these functions is otherwise
+# broken on your system.
+EnableMMAP On
+EnableSendfile Off
+
+# FileETag: Configures the file attributes that are used to create
+# the ETag (entity tag) response header field when the document is
+# based on a static file. (The ETag value is used in cache management
+# to save network bandwidth.)
+FileETag MTime Size
+
+# ContentDigest: This directive enables the generation of Content-MD5
+# headers as defined in RFC1864 respectively RFC2616.
+# The Content-MD5 header provides an end-to-end message integrity
+# check (MIC) of the entity-body. A proxy or client may check this
+# header for detecting accidental modification of the entity-body
+# in transit.
+# Note that this can cause performance problems on your server since
+# the message digest is computed on every request (the values are
+# not cached).
+# Content-MD5 is only sent for documents served by the core, and not
+# by any module. For example, SSI documents, output from CGI scripts,
+# and byte range responses do not have this header.
+ContentDigest Off
+
+# ErrorLog: The location of the error log file.
+# If you do not specify an ErrorLog directive within a
+# container, error messages relating to that virtual host will be
+# logged here. If you *do* define an error logfile for a
+# container, that host's errors will be logged there and not here.
+ErrorLog /var/log/apache2/error_log
+
+# LogLevel: Control the number of messages logged to the error_log.
+# Possible values include: debug, info, notice, warn, error, crit,
+# alert, emerg.
+LogLevel warn
+
+# We configure the "default" to be a very restrictive set of features.
+
+ Options FollowSymLinks
+ AllowOverride None
+ Require all denied
+
+
+# DirectoryIndex: sets the file that Apache will serve if a directory
+# is requested.
+#
+# The index.html.var file (a type-map) is used to deliver content-
+# negotiated documents. The MultiViews Options can be used for the
+# same purpose, but it is much slower.
+#
+# Do not change this entry unless you know what you are doing.
+
+ DirectoryIndex index.html index.html.var
+
+
+# The following lines prevent .htaccess and .htpasswd files from being
+# viewed by Web clients.
+
+ Require all denied
+
+
+# vim: ts=4 filetype=apache
diff --git a/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/modules.d/00_error_documents.conf b/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/modules.d/00_error_documents.conf
new file mode 100644
index 000000000..61479fa53
--- /dev/null
+++ b/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/modules.d/00_error_documents.conf
@@ -0,0 +1,57 @@
+# The configuration below implements multi-language error documents through
+# content-negotiation.
+
+# Customizable error responses come in three flavors:
+# 1) plain text 2) local redirects 3) external redirects
+# Some examples:
+#ErrorDocument 500 "The server made a boo boo."
+#ErrorDocument 404 /missing.html
+#ErrorDocument 404 "/cgi-bin/missing_handler.pl"
+#ErrorDocument 402 http://www.example.com/subscription_info.html
+
+# Required modules: mod_alias, mod_include, mod_negotiation
+# We use Alias to redirect any /error/HTTP_.html.var response to
+# our collection of by-error message multi-language collections. We use
+# includes to substitute the appropriate text.
+# You can modify the messages' appearance without changing any of the
+# default HTTP_.html.var files by adding the line:
+# Alias /error/include/ "/your/include/path/"
+# which allows you to create your own set of files by starting with the
+# /var/www/localhost/error/include/ files and copying them to /your/include/path/,
+# even on a per-VirtualHost basis. The default include files will display
+# your Apache version number and your ServerAdmin email address regardless
+# of the setting of ServerSignature.
+
+
+Alias /error/ "/usr/share/apache2/error/"
+
+
+ AllowOverride None
+ Options IncludesNoExec
+ AddOutputFilter Includes html
+ AddHandler type-map var
+ Require all granted
+ LanguagePriority en cs de es fr it ja ko nl pl pt-br ro sv tr
+ ForceLanguagePriority Prefer Fallback
+
+
+ErrorDocument 400 /error/HTTP_BAD_REQUEST.html.var
+ErrorDocument 401 /error/HTTP_UNAUTHORIZED.html.var
+ErrorDocument 403 /error/HTTP_FORBIDDEN.html.var
+ErrorDocument 404 /error/HTTP_NOT_FOUND.html.var
+ErrorDocument 405 /error/HTTP_METHOD_NOT_ALLOWED.html.var
+ErrorDocument 408 /error/HTTP_REQUEST_TIME_OUT.html.var
+ErrorDocument 410 /error/HTTP_GONE.html.var
+ErrorDocument 411 /error/HTTP_LENGTH_REQUIRED.html.var
+ErrorDocument 412 /error/HTTP_PRECONDITION_FAILED.html.var
+ErrorDocument 413 /error/HTTP_REQUEST_ENTITY_TOO_LARGE.html.var
+ErrorDocument 414 /error/HTTP_REQUEST_URI_TOO_LARGE.html.var
+ErrorDocument 415 /error/HTTP_UNSUPPORTED_MEDIA_TYPE.html.var
+ErrorDocument 500 /error/HTTP_INTERNAL_SERVER_ERROR.html.var
+ErrorDocument 501 /error/HTTP_NOT_IMPLEMENTED.html.var
+ErrorDocument 502 /error/HTTP_BAD_GATEWAY.html.var
+ErrorDocument 503 /error/HTTP_SERVICE_UNAVAILABLE.html.var
+ErrorDocument 506 /error/HTTP_VARIANT_ALSO_VARIES.html.var
+
+
+# vim: ts=4 filetype=apache
diff --git a/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/modules.d/00_languages.conf b/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/modules.d/00_languages.conf
new file mode 100644
index 000000000..c429bf94c
--- /dev/null
+++ b/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/modules.d/00_languages.conf
@@ -0,0 +1,133 @@
+# Settings for hosting different languages.
+
+# DefaultLanguage and AddLanguage allows you to specify the language of
+# a document. You can then use content negotiation to give a browser a
+# file in a language the user can understand.
+#
+# Specify a default language. This means that all data
+# going out without a specific language tag (see below) will
+# be marked with this one. You probably do NOT want to set
+# this unless you are sure it is correct for all cases.
+#
+# It is generally better to not mark a page as
+# being a certain language than marking it with the wrong
+# language!
+#
+# DefaultLanguage nl
+#
+# Note 1: The suffix does not have to be the same as the language
+# keyword --- those with documents in Polish (whose net-standard
+# language code is pl) may wish to use "AddLanguage pl .po" to
+# avoid the ambiguity with the common suffix for perl scripts.
+#
+# Note 2: The example entries below illustrate that in some cases
+# the two character 'Language' abbreviation is not identical to
+# the two character 'Country' code for its country,
+# E.g. 'Danmark/dk' versus 'Danish/da'.
+#
+# Note 3: In the case of 'ltz' we violate the RFC by using a three char
+# specifier. There is 'work in progress' to fix this and get
+# the reference data for rfc1766 cleaned up.
+#
+# Catalan (ca) - Croatian (hr) - Czech (cs) - Danish (da) - Dutch (nl)
+# English (en) - Esperanto (eo) - Estonian (et) - French (fr) - German (de)
+# Greek-Modern (el) - Hebrew (he) - Italian (it) - Japanese (ja)
+# Korean (ko) - Luxembourgeois* (ltz) - Norwegian Nynorsk (nn)
+# Norwegian (no) - Polish (pl) - Portugese (pt)
+# Brazilian Portuguese (pt-BR) - Russian (ru) - Swedish (sv)
+# Simplified Chinese (zh-CN) - Spanish (es) - Traditional Chinese (zh-TW)
+AddLanguage ca .ca
+AddLanguage cs .cz .cs
+AddLanguage da .dk
+AddLanguage de .de
+AddLanguage el .el
+AddLanguage en .en
+AddLanguage eo .eo
+AddLanguage es .es
+AddLanguage et .et
+AddLanguage fr .fr
+AddLanguage he .he
+AddLanguage hr .hr
+AddLanguage it .it
+AddLanguage ja .ja
+AddLanguage ko .ko
+AddLanguage ltz .ltz
+AddLanguage nl .nl
+AddLanguage nn .nn
+AddLanguage no .no
+AddLanguage pl .po
+AddLanguage pt .pt
+AddLanguage pt-BR .pt-br
+AddLanguage ru .ru
+AddLanguage sv .sv
+AddLanguage zh-CN .zh-cn
+AddLanguage zh-TW .zh-tw
+
+# LanguagePriority allows you to give precedence to some languages
+# in case of a tie during content negotiation.
+#
+# Just list the languages in decreasing order of preference. We have
+# more or less alphabetized them here. You probably want to change this.
+LanguagePriority en ca cs da de el eo es et fr he hr it ja ko ltz nl nn no pl pt pt-BR ru sv zh-CN zh-TW
+
+# ForceLanguagePriority allows you to serve a result page rather than
+# MULTIPLE CHOICES (Prefer) [in case of a tie] or NOT ACCEPTABLE (Fallback)
+# [in case no accepted languages matched the available variants]
+ForceLanguagePriority Prefer Fallback
+
+# Commonly used filename extensions to character sets. You probably
+# want to avoid clashes with the language extensions, unless you
+# are good at carefully testing your setup after each change.
+# See http://www.iana.org/assignments/character-sets for the
+# official list of charset names and their respective RFCs.
+AddCharset us-ascii.ascii .us-ascii
+AddCharset ISO-8859-1 .iso8859-1 .latin1
+AddCharset ISO-8859-2 .iso8859-2 .latin2 .cen
+AddCharset ISO-8859-3 .iso8859-3 .latin3
+AddCharset ISO-8859-4 .iso8859-4 .latin4
+AddCharset ISO-8859-5 .iso8859-5 .cyr .iso-ru
+AddCharset ISO-8859-6 .iso8859-6 .arb .arabic
+AddCharset ISO-8859-7 .iso8859-7 .grk .greek
+AddCharset ISO-8859-8 .iso8859-8 .heb .hebrew
+AddCharset ISO-8859-9 .iso8859-9 .latin5 .trk
+AddCharset ISO-8859-10 .iso8859-10 .latin6
+AddCharset ISO-8859-13 .iso8859-13
+AddCharset ISO-8859-14 .iso8859-14 .latin8
+AddCharset ISO-8859-15 .iso8859-15 .latin9
+AddCharset ISO-8859-16 .iso8859-16 .latin10
+AddCharset ISO-2022-JP .iso2022-jp .jis
+AddCharset ISO-2022-KR .iso2022-kr .kis
+AddCharset ISO-2022-CN .iso2022-cn .cis
+AddCharset Big5.Big5 .big5 .b5
+AddCharset cn-Big5 .cn-big5
+# For russian, more than one charset is used (depends on client, mostly):
+AddCharset WINDOWS-1251 .cp-1251 .win-1251
+AddCharset CP866 .cp866
+AddCharset KOI8 .koi8
+AddCharset KOI8-E .koi8-e
+AddCharset KOI8-r .koi8-r .koi8-ru
+AddCharset KOI8-U .koi8-u
+AddCharset KOI8-ru .koi8-uk .ua
+AddCharset ISO-10646-UCS-2 .ucs2
+AddCharset ISO-10646-UCS-4 .ucs4
+AddCharset UTF-7 .utf7
+AddCharset UTF-8 .utf8
+AddCharset UTF-16 .utf16
+AddCharset UTF-16BE .utf16be
+AddCharset UTF-16LE .utf16le
+AddCharset UTF-32 .utf32
+AddCharset UTF-32BE .utf32be
+AddCharset UTF-32LE .utf32le
+AddCharset euc-cn .euc-cn
+AddCharset euc-gb .euc-gb
+AddCharset euc-jp .euc-jp
+AddCharset euc-kr .euc-kr
+# Not sure how euc-tw got in - IANA doesn't list it???
+AddCharset EUC-TW .euc-tw
+AddCharset gb2312 .gb2312 .gb
+AddCharset iso-10646-ucs-2 .ucs-2 .iso-10646-ucs-2
+AddCharset iso-10646-ucs-4 .ucs-4 .iso-10646-ucs-4
+AddCharset shift_jis .shift_jis .sjis
+
+
+# vim: ts=4 filetype=apache
diff --git a/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/modules.d/00_mod_autoindex.conf b/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/modules.d/00_mod_autoindex.conf
new file mode 100644
index 000000000..10bf48317
--- /dev/null
+++ b/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/modules.d/00_mod_autoindex.conf
@@ -0,0 +1,85 @@
+
+
+
+
+# We include the /icons/ alias for FancyIndexed directory listings. If
+# you do not use FancyIndexing, you may comment this out.
+Alias /icons/ "/usr/share/apache2/icons/"
+
+
+ Options Indexes MultiViews
+ AllowOverride None
+ Require all granted
+
+
+
+# Directives controlling the display of server-generated directory listings.
+#
+# To see the listing of a directory, the Options directive for the
+# directory must include "Indexes", and the directory must not contain
+# a file matching those listed in the DirectoryIndex directive.
+
+# IndexOptions: Controls the appearance of server-generated directory
+# listings.
+IndexOptions FancyIndexing VersionSort
+
+# AddIcon* directives tell the server which icon to show for different
+# files or filename extensions. These are only displayed for
+# FancyIndexed directories.
+AddIconByEncoding (CMP,/icons/compressed.gif) x-compress x-gzip
+
+AddIconByType (TXT,/icons/text.gif) text/*
+AddIconByType (IMG,/icons/image2.gif) image/*
+AddIconByType (SND,/icons/sound2.gif) audio/*
+AddIconByType (VID,/icons/movie.gif) video/*
+
+AddIcon /icons/binary.gif .bin .exe
+AddIcon /icons/binhex.gif .hqx
+AddIcon /icons/tar.gif .tar
+AddIcon /icons/world2.gif .wrl .wrl.gz .vrml .vrm .iv
+AddIcon /icons/compressed.gif .Z .z .tgz .gz .zip
+AddIcon /icons/a.gif .ps .ai .eps
+AddIcon /icons/layout.gif .html .shtml .htm .pdf
+AddIcon /icons/text.gif .txt
+AddIcon /icons/c.gif .c
+AddIcon /icons/p.gif .pl .py
+AddIcon /icons/f.gif .for
+AddIcon /icons/dvi.gif .dvi
+AddIcon /icons/uuencoded.gif .uu
+AddIcon /icons/script.gif .conf .sh .shar .csh .ksh .tcl
+AddIcon /icons/tex.gif .tex
+AddIcon /icons/bomb.gif core
+
+AddIcon /icons/back.gif ..
+AddIcon /icons/hand.right.gif README
+AddIcon /icons/folder.gif ^^DIRECTORY^^
+AddIcon /icons/blank.gif ^^BLANKICON^^
+
+# DefaultIcon is which icon to show for files which do not have an icon
+# explicitly set.
+DefaultIcon /icons/unknown.gif
+
+# AddDescription allows you to place a short description after a file in
+# server-generated indexes. These are only displayed for FancyIndexed
+# directories.
+# Format: AddDescription "description" filename
+
+#AddDescription "GZIP compressed document" .gz
+#AddDescription "tar archive" .tar
+#AddDescription "GZIP compressed tar archive" .tgz
+
+# ReadmeName is the name of the README file the server will look for by
+# default, and append to directory listings.
+
+# HeaderName is the name of a file which should be prepended to
+# directory indexes.
+ReadmeName README.html
+HeaderName HEADER.html
+
+# IndexIgnore is a set of filenames which directory indexing should ignore
+# and not include in the listing. Shell-style wildcarding is permitted.
+IndexIgnore .??* *~ *# HEADER* README* RCS CVS *,v *,t
+
+
+
+# vim: ts=4 filetype=apache
diff --git a/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/modules.d/00_mod_info.conf b/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/modules.d/00_mod_info.conf
new file mode 100644
index 000000000..2cd32c477
--- /dev/null
+++ b/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/modules.d/00_mod_info.conf
@@ -0,0 +1,10 @@
+
+# Allow remote server configuration reports, with the URL of
+# http://servername/server-info
+
+ SetHandler server-info
+ Require local
+
+
+
+# vim: ts=4 filetype=apache
diff --git a/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/modules.d/00_mod_log_config.conf b/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/modules.d/00_mod_log_config.conf
new file mode 100644
index 000000000..ce0238eee
--- /dev/null
+++ b/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/modules.d/00_mod_log_config.conf
@@ -0,0 +1,35 @@
+
+# The following directives define some format nicknames for use with
+# a CustomLog directive (see below).
+LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
+LogFormat "%h %l %u %t \"%r\" %>s %b" common
+
+LogFormat "%{Referer}i -> %U" referer
+LogFormat "%{User-Agent}i" agent
+LogFormat "%v %h %l %u %t \"%r\" %>s %b %T" script
+LogFormat "%v %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" VLOG=%{VLOG}e" vhost
+
+
+# You need to enable mod_logio.c to use %I and %O
+LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio
+LogFormat "%v %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" vhostio
+
+
+# The location and format of the access logfile (Common Logfile Format).
+# If you do not define any access logfiles within a
+# container, they will be logged here. Contrariwise, if you *do*
+# define per- access logfiles, transactions will be
+# logged therein and *not* in this file.
+CustomLog /var/log/apache2/access_log common
+
+# If you would like to have agent and referer logfiles,
+# uncomment the following directives.
+#CustomLog /var/log/apache2/referer_log referer
+#CustomLog /var/log/apache2/agent_logs agent
+
+# If you prefer a logfile with access, agent, and referer information
+# (Combined Logfile Format) you can use the following directive.
+#CustomLog /var/log/apache2/access_log combined
+
+
+# vim: ts=4 filetype=apache
diff --git a/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/modules.d/00_mod_mime.conf b/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/modules.d/00_mod_mime.conf
new file mode 100644
index 000000000..fb8a9a5d5
--- /dev/null
+++ b/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/modules.d/00_mod_mime.conf
@@ -0,0 +1,46 @@
+
+# TypesConfig points to the file containing the list of mappings from
+# filename extension to MIME-type.
+TypesConfig /etc/mime.types
+
+# AddType allows you to add to or override the MIME configuration
+# file specified in TypesConfig for specific file types.
+#AddType application/x-gzip .tgz
+
+# AddEncoding allows you to have certain browsers uncompress
+# information on the fly. Note: Not all browsers support this.
+#AddEncoding x-compress .Z
+#AddEncoding x-gzip .gz .tgz
+
+# If the AddEncoding directives above are commented-out, then you
+# probably should define those extensions to indicate media types:
+AddType application/x-compress .Z
+AddType application/x-gzip .gz .tgz
+
+# AddHandler allows you to map certain file extensions to "handlers":
+# actions unrelated to filetype. These can be either built into the server
+# or added with the Action directive (see below)
+
+# To use CGI scripts outside of ScriptAliased directories:
+# (You will also need to add "ExecCGI" to the "Options" directive.)
+#AddHandler cgi-script .cgi
+
+# For type maps (negotiated resources):
+#AddHandler type-map var
+
+# Filters allow you to process content before it is sent to the client.
+#
+# To parse .shtml files for server-side includes (SSI):
+# (You will also need to add "Includes" to the "Options" directive.)
+#AddType text/html .shtml
+#AddOutputFilter INCLUDES .shtml
+
+
+
+# The mod_mime_magic module allows the server to use various hints from the
+# contents of the file itself to determine its type. The MIMEMagicFile
+# directive tells the module where the hint definitions are located.
+MIMEMagicFile /etc/apache2/magic
+
+
+# vim: ts=4 filetype=apache
diff --git a/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/modules.d/00_mod_status.conf b/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/modules.d/00_mod_status.conf
new file mode 100644
index 000000000..ed8b3c7cb
--- /dev/null
+++ b/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/modules.d/00_mod_status.conf
@@ -0,0 +1,15 @@
+
+# Allow server status reports generated by mod_status,
+# with the URL of http://servername/server-status
+
+ SetHandler server-status
+ Require local
+
+
+# ExtendedStatus controls whether Apache will generate "full" status
+# information (ExtendedStatus On) or just basic information (ExtendedStatus
+# Off) when the "server-status" handler is called.
+ExtendedStatus On
+
+
+# vim: ts=4 filetype=apache
diff --git a/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/modules.d/00_mod_userdir.conf b/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/modules.d/00_mod_userdir.conf
new file mode 100644
index 000000000..0087126c4
--- /dev/null
+++ b/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/modules.d/00_mod_userdir.conf
@@ -0,0 +1,32 @@
+# Settings for user home directories
+
+# UserDir: The name of the directory that is appended onto a user's home
+# directory if a ~user request is received. Note that you must also set
+# the default access control for these directories, as in the example below.
+UserDir public_html
+
+# Control access to UserDir directories. The following is an example
+# for a site where these directories are restricted to read-only.
+
+ AllowOverride FileInfo AuthConfig Limit Indexes
+ Options MultiViews Indexes SymLinksIfOwnerMatch IncludesNoExec
+
+ Require all granted
+
+
+ Require all denied
+
+
+
+# Suexec isn't really required to run cgi-scripts, but it's a really good
+# idea if you have multiple users serving websites...
+
+
+ Options ExecCGI
+ SetHandler cgi-script
+
+
+
+
+
+# vim: ts=4 filetype=apache
diff --git a/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/modules.d/00_mpm.conf b/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/modules.d/00_mpm.conf
new file mode 100644
index 000000000..bcb9b6b47
--- /dev/null
+++ b/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/modules.d/00_mpm.conf
@@ -0,0 +1,99 @@
+# Server-Pool Management (MPM specific)
+
+# PidFile: The file in which the server should record its process
+# identification number when it starts.
+#
+# DO NOT CHANGE UNLESS YOU KNOW WHAT YOU ARE DOING
+PidFile /run/apache2.pid
+
+# The accept serialization lock file MUST BE STORED ON A LOCAL DISK.
+# Mutex file:/run/apache_mpm_mutex
+
+# Only one of the below sections will be relevant on your
+# installed httpd. Use "/usr/sbin/apache2 -l" to find out the
+# active mpm.
+
+# common MPM configuration
+# These configuration directives apply to all MPMs
+#
+# StartServers: Number of child server processes created at startup
+# MaxRequestWorkers: Maximum number of child processes to serve requests
+# MaxConnectionsPerChild: Limit on the number of connections that an individual
+# child server will handle during its life
+
+
+# prefork MPM
+# This is the default MPM if USE=-threads
+#
+# MinSpareServers: Minimum number of idle child server processes
+# MaxSpareServers: Maximum number of idle child server processes
+
+ StartServers 5
+ MinSpareServers 5
+ MaxSpareServers 10
+ MaxRequestWorkers 150
+ MaxConnectionsPerChild 10000
+
+
+# worker MPM
+# This is the default MPM if USE=threads
+#
+# MinSpareThreads: Minimum number of idle threads available to handle request spikes
+# MaxSpareThreads: Maximum number of idle threads
+# ThreadsPerChild: Number of threads created by each child process
+
+ StartServers 2
+ MinSpareThreads 25
+ MaxSpareThreads 75
+ ThreadsPerChild 25
+ MaxRequestWorkers 150
+ MaxConnectionsPerChild 10000
+
+
+# event MPM
+#
+# MinSpareThreads: Minimum number of idle threads available to handle request spikes
+# MaxSpareThreads: Maximum number of idle threads
+# ThreadsPerChild: Number of threads created by each child process
+
+ StartServers 2
+ MinSpareThreads 25
+ MaxSpareThreads 75
+ ThreadsPerChild 25
+ MaxRequestWorkers 150
+ MaxConnectionsPerChild 10000
+
+
+# peruser MPM
+#
+# MinSpareProcessors: Minimum number of idle child server processes
+# MinProcessors: Minimum number of processors per virtual host
+# MaxProcessors: Maximum number of processors per virtual host
+# ExpireTimeout: Maximum idle time before a child is killed, 0 to disable
+# Multiplexer: Specify a Multiplexer child configuration.
+# Processor: Specify a user and group for a specific child process
+
+ MinSpareProcessors 2
+ MinProcessors 2
+ MaxProcessors 10
+ MaxRequestWorkers 150
+ MaxConnectionsPerChild 1000
+ ExpireTimeout 1800
+
+ Multiplexer nobody nobody
+ Processor apache apache
+
+
+# itk MPM
+#
+# MinSpareServers: Minimum number of idle child server processes
+# MaxSpareServers: Maximum number of idle child server processes
+
+ StartServers 5
+ MinSpareServers 5
+ MaxSpareServers 10
+ MaxRequestWorkers 150
+ MaxConnectionsPerChild 10000
+
+
+# vim: ts=4 filetype=apache
diff --git a/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/modules.d/10_mod_mem_cache.conf b/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/modules.d/10_mod_mem_cache.conf
new file mode 100644
index 000000000..520d9fd82
--- /dev/null
+++ b/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/modules.d/10_mod_mem_cache.conf
@@ -0,0 +1,10 @@
+
+# 128MB cache for objects < 2MB
+CacheEnable mem /
+MCacheSize 131072
+MCacheMaxObjectCount 1000
+MCacheMinObjectSize 1
+MCacheMaxObjectSize 2097152
+
+
+# vim: ts=4 filetype=apache
diff --git a/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/modules.d/40_mod_ssl.conf b/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/modules.d/40_mod_ssl.conf
new file mode 100644
index 000000000..f51de4641
--- /dev/null
+++ b/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/modules.d/40_mod_ssl.conf
@@ -0,0 +1,67 @@
+# Note: The following must must be present to support
+# starting without SSL on platforms with no /dev/random equivalent
+# but a statically compiled-in mod_ssl.
+
+SSLRandomSeed startup builtin
+SSLRandomSeed connect builtin
+
+
+
+# This is the Apache server configuration file providing SSL support.
+# It contains the configuration directives to instruct the server how to
+# serve pages over an https connection. For detailing information about these
+# directives see
+
+# Do NOT simply read the instructions in here without understanding
+# what they do. They're here only as hints or reminders. If you are unsure
+# consult the online docs. You have been warned.
+
+## Pseudo Random Number Generator (PRNG):
+# Configure one or more sources to seed the PRNG of the SSL library.
+# The seed data should be of good random quality.
+# WARNING! On some platforms /dev/random blocks if not enough entropy
+# is available. This means you then cannot use the /dev/random device
+# because it would lead to very long connection times (as long as
+# it requires to make more entropy available). But usually those
+# platforms additionally provide a /dev/urandom device which doesn't
+# block. So, if available, use this one instead. Read the mod_ssl User
+# Manual for more details.
+#SSLRandomSeed startup file:/dev/random 512
+#SSLRandomSeed startup file:/dev/urandom 512
+#SSLRandomSeed connect file:/dev/random 512
+#SSLRandomSeed connect file:/dev/urandom 512
+
+## SSL Global Context:
+# All SSL configuration in this context applies both to the main server and
+# all SSL-enabled virtual hosts.
+
+# Some MIME-types for downloading Certificates and CRLs
+
+ AddType application/x-x509-ca-cert .crt
+ AddType application/x-pkcs7-crl .crl
+
+
+## Pass Phrase Dialog:
+# Configure the pass phrase gathering process. The filtering dialog program
+# (`builtin' is a internal terminal dialog) has to provide the pass phrase on
+# stdout.
+SSLPassPhraseDialog builtin
+
+## Inter-Process Session Cache:
+# Configure the SSL Session Cache: First the mechanism to use and second the
+# expiring timeout (in seconds).
+#SSLSessionCache dbm:/run/ssl_scache
+SSLSessionCache shmcb:/run/ssl_scache(512000)
+SSLSessionCacheTimeout 300
+
+## Semaphore:
+# Configure the path to the mutual exclusion semaphore the SSL engine uses
+# internally for inter-process synchronization.
+Mutex file:/run/apache_ssl_mutex ssl-cache
+
+## SSL Compression:
+# Known to be vulnerable thus disabled by default (bug #507324).
+SSLCompression off
+
+
+# vim: ts=4 filetype=apache
diff --git a/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/modules.d/41_mod_http2.conf b/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/modules.d/41_mod_http2.conf
new file mode 100644
index 000000000..e4c9454e0
--- /dev/null
+++ b/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/modules.d/41_mod_http2.conf
@@ -0,0 +1,9 @@
+
+
+ # enable debugging for this module
+ #LogLevel http2:info
+
+ #Enable HTTP/2 support
+ Protocols h2 h2c http/1.1
+
+
diff --git a/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/modules.d/45_mod_dav.conf b/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/modules.d/45_mod_dav.conf
new file mode 100644
index 000000000..36f6b9cca
--- /dev/null
+++ b/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/modules.d/45_mod_dav.conf
@@ -0,0 +1,19 @@
+
+DavLockDB "/var/lib/dav/lockdb"
+
+# The following directives disable redirects on non-GET requests for
+# a directory that does not include the trailing slash. This fixes a
+# problem with several clients that do not appropriately handle
+# redirects for folders with DAV methods.
+
+BrowserMatch "Microsoft Data Access Internet Publishing Provider" redirect-carefully
+BrowserMatch "MS FrontPage" redirect-carefully
+BrowserMatch "^WebDrive" redirect-carefully
+BrowserMatch "^WebDAVFS/1.[012345678]" redirect-carefully
+BrowserMatch "^gnome-vfs/1.0" redirect-carefully
+BrowserMatch "^XML Spy" redirect-carefully
+BrowserMatch "^Dreamweaver-WebDAV-SCM1" redirect-carefully
+
+
+
+# vim: ts=4 filetype=apache
diff --git a/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/modules.d/46_mod_ldap.conf b/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/modules.d/46_mod_ldap.conf
new file mode 100644
index 000000000..883061fee
--- /dev/null
+++ b/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/modules.d/46_mod_ldap.conf
@@ -0,0 +1,18 @@
+# Examples below are taken from the online documentation
+# Refer to:
+# http://localhost/manual/mod/mod_ldap.html
+# http://localhost/manual/mod/mod_auth_ldap.html
+
+LDAPSharedCacheSize 200000
+LDAPCacheEntries 1024
+LDAPCacheTTL 600
+LDAPOpCacheEntries 1024
+LDAPOpCacheTTL 600
+
+
+ SetHandler ldap-status
+ Require local
+
+
+
+# vim: ts=4 filetype=apache
diff --git a/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/vhosts.d/.keep_www-servers_apache-2 b/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/vhosts.d/.keep_www-servers_apache-2
new file mode 100644
index 000000000..e69de29bb
diff --git a/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/vhosts.d/00_default_ssl_vhost.conf b/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/vhosts.d/00_default_ssl_vhost.conf
new file mode 100644
index 000000000..bb395473c
--- /dev/null
+++ b/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/vhosts.d/00_default_ssl_vhost.conf
@@ -0,0 +1,191 @@
+
+
+
+# see bug #178966 why this is in here
+
+# When we also provide SSL we have to listen to the HTTPS port
+# Note: Configurations that use IPv6 but not IPv4-mapped addresses need two
+# Listen directives: "Listen [::]:443" and "Listen 0.0.0.0:443"
+Listen 443
+
+
+ ServerName localhost
+ Include /etc/apache2/vhosts.d/default_vhost.include
+ ErrorLog /var/log/apache2/ssl_error_log
+
+
+ TransferLog /var/log/apache2/ssl_access_log
+
+
+ ## SSL Engine Switch:
+ # Enable/Disable SSL for this virtual host.
+ SSLEngine on
+
+ ## SSLProtocol:
+ # Don't use SSLv2 anymore as it's considered to be broken security-wise.
+ # Also disable SSLv3 as most modern browsers are capable of TLS.
+ SSLProtocol ALL -SSLv2 -SSLv3
+
+ ## SSL Cipher Suite:
+ # List the ciphers that the client is permitted to negotiate.
+ # See the mod_ssl documentation for a complete list.
+ # This list of ciphers is recommended by mozilla and was stripped off
+ # its RC4 ciphers. (bug #506924)
+ SSLCipherSuite ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128:AES256:HIGH:!RC4:!aNULL:!eNULL:!EXPORT:!DES:!3DES:!MD5:!PSK
+
+ ## SSLHonorCipherOrder:
+ # Prefer the server's cipher preference order as the client may have a
+ # weak default order.
+ SSLHonorCipherOrder On
+
+ ## Server Certificate:
+ # Point SSLCertificateFile at a PEM encoded certificate. If the certificate
+ # is encrypted, then you will be prompted for a pass phrase. Note that a
+ # kill -HUP will prompt again. Keep in mind that if you have both an RSA
+ # and a DSA certificate you can configure both in parallel (to also allow
+ # the use of DSA ciphers, etc.)
+ SSLCertificateFile /etc/ssl/apache2/server.crt
+
+ ## Server Private Key:
+ # If the key is not combined with the certificate, use this directive to
+ # point at the key file. Keep in mind that if you've both a RSA and a DSA
+ # private key you can configure both in parallel (to also allow the use of
+ # DSA ciphers, etc.)
+ SSLCertificateKeyFile /etc/ssl/apache2/server.key
+
+ ## Server Certificate Chain:
+ # Point SSLCertificateChainFile at a file containing the concatenation of
+ # PEM encoded CA certificates which form the certificate chain for the
+ # server certificate. Alternatively the referenced file can be the same as
+ # SSLCertificateFile when the CA certificates are directly appended to the
+ # server certificate for convinience.
+ #SSLCertificateChainFile /etc/ssl/apache2/ca.crt
+
+ ## Certificate Authority (CA):
+ # Set the CA certificate verification path where to find CA certificates
+ # for client authentication or alternatively one huge file containing all
+ # of them (file must be PEM encoded).
+ # Note: Inside SSLCACertificatePath you need hash symlinks to point to the
+ # certificate files. Use the provided Makefile to update the hash symlinks
+ # after changes.
+ #SSLCACertificatePath /etc/ssl/apache2/ssl.crt
+ #SSLCACertificateFile /etc/ssl/apache2/ca-bundle.crt
+
+ ## Certificate Revocation Lists (CRL):
+ # Set the CA revocation path where to find CA CRLs for client authentication
+ # or alternatively one huge file containing all of them (file must be PEM
+ # encoded).
+ # Note: Inside SSLCARevocationPath you need hash symlinks to point to the
+ # certificate files. Use the provided Makefile to update the hash symlinks
+ # after changes.
+ #SSLCARevocationPath /etc/ssl/apache2/ssl.crl
+ #SSLCARevocationFile /etc/ssl/apache2/ca-bundle.crl
+
+ ## Client Authentication (Type):
+ # Client certificate verification type and depth. Types are none, optional,
+ # require and optional_no_ca. Depth is a number which specifies how deeply
+ # to verify the certificate issuer chain before deciding the certificate is
+ # not valid.
+ #SSLVerifyClient require
+ #SSLVerifyDepth 10
+
+ ## Access Control:
+ # With SSLRequire you can do per-directory access control based on arbitrary
+ # complex boolean expressions containing server variable checks and other
+ # lookup directives. The syntax is a mixture between C and Perl. See the
+ # mod_ssl documentation for more details.
+ #
+ # #SSLRequire ( %{SSL_CIPHER} !~ m/^(EXP|NULL)/ \
+ # and %{SSL_CLIENT_S_DN_O} eq "Snake Oil, Ltd." \
+ # and %{SSL_CLIENT_S_DN_OU} in {"Staff", "CA", "Dev"} \
+ # and %{TIME_WDAY} >= 1 and %{TIME_WDAY} <= 5 \
+ # and %{TIME_HOUR} >= 8 and %{TIME_HOUR} <= 20 ) \
+ # or %{REMOTE_ADDR} =~ m/^192\.76\.162\.[0-9]+$/
+ #
+
+ ## SSL Engine Options:
+ # Set various options for the SSL engine.
+
+ ## FakeBasicAuth:
+ # Translate the client X.509 into a Basic Authorisation. This means that the
+ # standard Auth/DBMAuth methods can be used for access control. The user
+ # name is the `one line' version of the client's X.509 certificate.
+ # Note that no password is obtained from the user. Every entry in the user
+ # file needs this password: `xxj31ZMTZzkVA'.
+
+ ## ExportCertData:
+ # This exports two additional environment variables: SSL_CLIENT_CERT and
+ # SSL_SERVER_CERT. These contain the PEM-encoded certificates of the server
+ # (always existing) and the client (only existing when client
+ # authentication is used). This can be used to import the certificates into
+ # CGI scripts.
+
+ ## StdEnvVars:
+ # This exports the standard SSL/TLS related `SSL_*' environment variables.
+ # Per default this exportation is switched off for performance reasons,
+ # because the extraction step is an expensive operation and is usually
+ # useless for serving static content. So one usually enables the exportation
+ # for CGI and SSI requests only.
+
+ ## StrictRequire:
+ # This denies access when "SSLRequireSSL" or "SSLRequire" applied even under
+ # a "Satisfy any" situation, i.e. when it applies access is denied and no
+ # other module can change it.
+
+ ## OptRenegotiate:
+ # This enables optimized SSL connection renegotiation handling when SSL
+ # directives are used in per-directory context.
+ #SSLOptions +FakeBasicAuth +ExportCertData +StrictRequire
+
+ SSLOptions +StdEnvVars
+
+
+
+ SSLOptions +StdEnvVars
+
+
+ ## SSL Protocol Adjustments:
+ # The safe and default but still SSL/TLS standard compliant shutdown
+ # approach is that mod_ssl sends the close notify alert but doesn't wait
+ # for the close notify alert from client. When you need a different
+ # shutdown approach you can use one of the following variables:
+
+ ## ssl-unclean-shutdown:
+ # This forces an unclean shutdown when the connection is closed, i.e. no
+ # SSL close notify alert is send or allowed to received. This violates the
+ # SSL/TLS standard but is needed for some brain-dead browsers. Use this when
+ # you receive I/O errors because of the standard approach where mod_ssl
+ # sends the close notify alert.
+
+ ## ssl-accurate-shutdown:
+ # This forces an accurate shutdown when the connection is closed, i.e. a
+ # SSL close notify alert is send and mod_ssl waits for the close notify
+ # alert of the client. This is 100% SSL/TLS standard compliant, but in
+ # practice often causes hanging connections with brain-dead browsers. Use
+ # this only for browsers where you know that their SSL implementation works
+ # correctly.
+ # Notice: Most problems of broken clients are also related to the HTTP
+ # keep-alive facility, so you usually additionally want to disable
+ # keep-alive for those clients, too. Use variable "nokeepalive" for this.
+ # Similarly, one has to force some clients to use HTTP/1.0 to workaround
+ # their broken HTTP/1.1 implementation. Use variables "downgrade-1.0" and
+ # "force-response-1.0" for this.
+
+ BrowserMatch ".*MSIE.*" \
+ nokeepalive ssl-unclean-shutdown \
+ downgrade-1.0 force-response-1.0
+
+
+ ## Per-Server Logging:
+ # The home of a custom SSL log file. Use this when you want a compact
+ # non-error SSL logfile on a virtual host basis.
+
+ CustomLog /var/log/apache2/ssl_request_log \
+ "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"
+
+
+
+
+
+
+# vim: ts=4 filetype=apache
diff --git a/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/vhosts.d/00_default_vhost.conf b/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/vhosts.d/00_default_vhost.conf
new file mode 100644
index 000000000..b9766b5f1
--- /dev/null
+++ b/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/vhosts.d/00_default_vhost.conf
@@ -0,0 +1,45 @@
+# Virtual Hosts
+#
+# If you want to maintain multiple domains/hostnames on your
+# machine you can setup VirtualHost containers for them. Most configurations
+# use only name-based virtual hosts so the server doesn't need to worry about
+# IP addresses. This is indicated by the asterisks in the directives below.
+#
+# Please see the documentation at
+#
+# for further details before you try to setup virtual hosts.
+#
+# You may use the command line option '-S' to verify your virtual host
+# configuration.
+
+
+# see bug #178966 why this is in here
+
+# Listen: Allows you to bind Apache to specific IP addresses and/or
+# ports, instead of the default. See also the
+# directive.
+#
+# Change this to Listen on specific IP addresses as shown below to
+# prevent Apache from glomming onto all bound IP addresses.
+#
+#Listen 12.34.56.78:80
+Listen 80
+
+# When virtual hosts are enabled, the main host defined in the default
+# httpd.conf configuration will go away. We redefine it here so that it is
+# still available.
+#
+# If you disable this vhost by removing -D DEFAULT_VHOST from
+# /etc/conf.d/apache2, the first defined virtual host elsewhere will be
+# the default.
+
+ ServerName localhost
+ Include /etc/apache2/vhosts.d/default_vhost.include
+
+
+ ServerEnvironment apache apache
+
+
+
+
+# vim: ts=4 filetype=apache
diff --git a/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/vhosts.d/default_vhost.include b/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/vhosts.d/default_vhost.include
new file mode 100644
index 000000000..af6ece85b
--- /dev/null
+++ b/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/vhosts.d/default_vhost.include
@@ -0,0 +1,71 @@
+# ServerAdmin: Your address, where problems with the server should be
+# e-mailed. This address appears on some server-generated pages, such
+# as error documents. e.g. admin@your-domain.com
+ServerAdmin root@localhost
+
+# DocumentRoot: The directory out of which you will serve your
+# documents. By default, all requests are taken from this directory, but
+# symbolic links and aliases may be used to point to other locations.
+#
+# If you change this to something that isn't under /var/www then suexec
+# will no longer work.
+DocumentRoot "/var/www/localhost/htdocs"
+
+# This should be changed to whatever you set DocumentRoot to.
+
+ # Possible values for the Options directive are "None", "All",
+ # or any combination of:
+ # Indexes Includes FollowSymLinks SymLinksifOwnerMatch ExecCGI MultiViews
+ #
+ # Note that "MultiViews" must be named *explicitly* --- "Options All"
+ # doesn't give it to you.
+ #
+ # The Options directive is both complicated and important. Please see
+ # http://httpd.apache.org/docs/2.4/mod/core.html#options
+ # for more information.
+ Options Indexes FollowSymLinks
+
+ # AllowOverride controls what directives may be placed in .htaccess files.
+ # It can be "All", "None", or any combination of the keywords:
+ # Options FileInfo AuthConfig Limit
+ AllowOverride All
+
+ # Controls who can get stuff from this server.
+ Require all granted
+
+
+
+ # Redirect: Allows you to tell clients about documents that used to
+ # exist in your server's namespace, but do not anymore. The client
+ # will make a new request for the document at its new location.
+ # Example:
+ # Redirect permanent /foo http://www.example.com/bar
+
+ # Alias: Maps web paths into filesystem paths and is used to
+ # access content that does not live under the DocumentRoot.
+ # Example:
+ # Alias /webpath /full/filesystem/path
+ #
+ # If you include a trailing / on /webpath then the server will
+ # require it to be present in the URL. You will also likely
+ # need to provide a section to allow access to
+ # the filesystem path.
+
+ # ScriptAlias: This controls which directories contain server scripts.
+ # ScriptAliases are essentially the same as Aliases, except that
+ # documents in the target directory are treated as applications and
+ # run by the server when requested rather than as documents sent to the
+ # client. The same rules about trailing "/" apply to ScriptAlias
+ # directives as to Alias.
+ ScriptAlias /cgi-bin/ "/var/www/localhost/cgi-bin/"
+
+
+# "/var/www/localhost/cgi-bin" should be changed to whatever your ScriptAliased
+# CGI directory exists, if you have that configured.
+
+ AllowOverride None
+ Options None
+ Require all granted
+
+
+# vim: ts=4 filetype=apache
diff --git a/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/vhosts.d/gentoo.example.com.conf b/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/vhosts.d/gentoo.example.com.conf
new file mode 100644
index 000000000..41de4d236
--- /dev/null
+++ b/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/apache2/vhosts.d/gentoo.example.com.conf
@@ -0,0 +1,7 @@
+
+ ServerName gentoo.example.com
+ ServerAdmin webmaster@localhost
+ DocumentRoot /var/www/html
+ ErrorLog ${APACHE_LOG_DIR}/error.log
+ CustomLog ${APACHE_LOG_DIR}/access.log combined
+
diff --git a/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/conf.d/apache2 b/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/conf.d/apache2
new file mode 100644
index 000000000..b7ecb4f2a
--- /dev/null
+++ b/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/conf.d/apache2
@@ -0,0 +1,74 @@
+# /etc/conf.d/apache2: config file for /etc/init.d/apache2
+
+# When you install a module it is easy to activate or deactivate the modules
+# and other features of apache using the APACHE2_OPTS line. Every module should
+# install a configuration in /etc/apache2/modules.d. In that file will have an
+# directive where NNN is the option to enable that module.
+#
+# Here are the options available in the default configuration:
+#
+# AUTH_DIGEST Enables mod_auth_digest
+# AUTHNZ_LDAP Enables authentication through mod_ldap (available if USE=ldap)
+# CACHE Enables mod_cache
+# DAV Enables mod_dav
+# ERRORDOCS Enables default error documents for many languages.
+# INFO Enables mod_info, a useful module for debugging
+# LANGUAGE Enables content-negotiation based on language and charset.
+# LDAP Enables mod_ldap (available if USE=ldap)
+# MANUAL Enables /manual/ to be the apache manual (available if USE=docs)
+# MEM_CACHE Enables default configuration mod_mem_cache
+# PROXY Enables mod_proxy
+# SSL Enables SSL (available if USE=ssl)
+# STATUS Enabled mod_status, a useful module for statistics
+# SUEXEC Enables running CGI scripts (in USERDIR) through suexec.
+# USERDIR Enables /~username mapping to /home/username/public_html
+#
+#
+# The following two options provide the default virtual host for the HTTP and
+# HTTPS protocol. YOU NEED TO ENABLE AT LEAST ONE OF THEM, otherwise apache
+# will not listen for incomming connections on the approriate port.
+#
+# DEFAULT_VHOST Enables name-based virtual hosts, with the default
+# virtual host being in /var/www/localhost/htdocs
+# SSL_DEFAULT_VHOST Enables default vhost for SSL (you should enable this
+# when you enable SSL)
+#
+APACHE2_OPTS="-D DEFAULT_VHOST -D INFO -D SSL -D SSL_DEFAULT_VHOST -D LANGUAGE"
+
+# Extended options for advanced uses of Apache ONLY
+# You don't need to edit these unless you are doing crazy Apache stuff
+# As not having them set correctly, or feeding in an incorrect configuration
+# via them will result in Apache failing to start
+# YOU HAVE BEEN WARNED.
+
+# PID file
+#PIDFILE=/var/run/apache2.pid
+
+# timeout for startup/shutdown checks
+#TIMEOUT=10
+
+# ServerRoot setting
+#SERVERROOT=/usr/lib64/apache2
+
+# Configuration file location
+# - If this does NOT start with a '/', then it is treated relative to
+# $SERVERROOT by Apache
+#CONFIGFILE=/etc/apache2/httpd.conf
+
+# Location to log startup errors to
+# They are normally dumped to your terminal.
+#STARTUPERRORLOG="/var/log/apache2/startuperror.log"
+
+# A command that outputs a formatted text version of the HTML at the URL
+# of the command line. Designed for lynx, however other programs may work.
+#LYNX="lynx -dump"
+
+# The URL to your server's mod_status status page.
+# Required for status and fullstatus
+#STATUSURL="http://localhost/server-status"
+
+# Method to use when reloading the server
+# Valid options are 'restart' and 'graceful'
+# See http://httpd.apache.org/docs/2.2/stopping.html for information on
+# what they do and how they differ.
+#RELOAD_TYPE="graceful"
diff --git a/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/sites b/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/sites
new file mode 100644
index 000000000..7f0b3a8b3
--- /dev/null
+++ b/certbot-apache/certbot_apache/tests/testdata/gentoo_apache/apache/sites
@@ -0,0 +1,3 @@
+vhosts.d/gentoo.example.com.conf, gentoo.example.com
+vhosts.d/00_default_vhost.conf, localhost
+vhosts.d/00_default_ssl_vhost.conf, localhost
diff --git a/certbot-apache/certbot_apache/tests/tls_sni_01_test.py b/certbot-apache/certbot_apache/tests/tls_sni_01_test.py
index 62464d5d0..6c37c2ecc 100644
--- a/certbot-apache/certbot_apache/tests/tls_sni_01_test.py
+++ b/certbot-apache/certbot_apache/tests/tls_sni_01_test.py
@@ -23,7 +23,8 @@ class TlsSniPerformTest(util.ApacheTest):
super(TlsSniPerformTest, self).setUp()
config = util.get_apache_configurator(
- self.config_path, self.vhost_path, self.config_dir, self.work_dir)
+ self.config_path, self.vhost_path, self.config_dir,
+ self.work_dir)
config.config.tls_sni_01_port = 443
from certbot_apache import tls_sni_01
@@ -41,8 +42,8 @@ class TlsSniPerformTest(util.ApacheTest):
@mock.patch("certbot.util.exe_exists")
@mock.patch("certbot.util.run_script")
def test_perform1(self, _, mock_exists):
- mock_register = mock.Mock()
- self.sni.configurator.reverter.register_undo_command = mock_register
+ self.sni.configurator.parser.modules.add("socache_shmcb_module")
+ self.sni.configurator.parser.modules.add("ssl_module")
mock_exists.return_value = True
self.sni.configurator.parser.update_runtime_variables = mock.Mock()
@@ -55,10 +56,6 @@ class TlsSniPerformTest(util.ApacheTest):
self.sni._setup_challenge_cert = mock_setup_cert
responses = self.sni.perform()
-
- # Make sure that register_undo_command was called into temp directory.
- self.assertEqual(True, mock_register.call_args[0][0])
-
mock_setup_cert.assert_called_once_with(achall)
# Check to make sure challenge config path is included in apache config
@@ -71,7 +68,7 @@ class TlsSniPerformTest(util.ApacheTest):
def test_perform2(self):
# Avoid load module
self.sni.configurator.parser.modules.add("ssl_module")
-
+ self.sni.configurator.parser.modules.add("socache_shmcb_module")
acme_responses = []
for achall in self.achalls:
self.sni.add_chall(achall)
@@ -81,7 +78,8 @@ class TlsSniPerformTest(util.ApacheTest):
# pylint: disable=protected-access
self.sni._setup_challenge_cert = mock_setup_cert
- with mock.patch("certbot_apache.configurator.ApacheConfigurator.enable_mod"):
+ with mock.patch(
+ "certbot_apache.override_debian.DebianConfigurator.enable_mod"):
sni_responses = self.sni.perform()
self.assertEqual(mock_setup_cert.call_count, 2)
diff --git a/certbot-apache/certbot_apache/tests/util.py b/certbot-apache/certbot_apache/tests/util.py
index 34d2476f7..2405110c5 100644
--- a/certbot-apache/certbot_apache/tests/util.py
+++ b/certbot-apache/certbot_apache/tests/util.py
@@ -1,5 +1,6 @@
"""Common utilities for certbot_apache."""
import os
+import shutil
import sys
import unittest
@@ -16,7 +17,7 @@ from certbot.plugins import common
from certbot.tests import util as test_util
from certbot_apache import configurator
-from certbot_apache import constants
+from certbot_apache import entrypoint
from certbot_apache import obj
@@ -38,6 +39,9 @@ class ApacheTest(unittest.TestCase): # pylint: disable=too-few-public-methods
self.rsa512jwk = jose.JWKRSA.load(test_util.load_vector(
"rsa512_key.pem"))
+ self.config = get_apache_configurator(self.config_path, vhost_root,
+ self.config_dir, self.work_dir)
+
# Make sure all vhosts in sites-enabled are symlinks (Python packaging
# does not preserve symlinks)
sites_enabled = os.path.join(self.config_path, "sites-enabled")
@@ -55,8 +59,13 @@ class ApacheTest(unittest.TestCase): # pylint: disable=too-few-public-methods
os.path.pardir, "sites-available", vhost_basename)
os.symlink(target, vhost)
+ def tearDown(self):
+ shutil.rmtree(self.temp_dir)
+ shutil.rmtree(self.config_dir)
+ shutil.rmtree(self.work_dir)
-class ParserTest(ApacheTest): # pytlint: disable=too-few-public-methods
+
+class ParserTest(ApacheTest):
def setUp(self, test_dir="debian_apache_2_4/multiple_vhosts",
config_root="debian_apache_2_4/multiple_vhosts/apache2",
@@ -72,12 +81,16 @@ class ParserTest(ApacheTest): # pytlint: disable=too-few-public-methods
with mock.patch("certbot_apache.parser.ApacheParser."
"update_runtime_variables"):
self.parser = ApacheParser(
- self.aug, self.config_path, self.vhost_path)
+ self.aug, self.config_path, self.vhost_path,
+ configurator=self.config)
-def get_apache_configurator(
+def get_apache_configurator( # pylint: disable=too-many-arguments, too-many-locals
config_path, vhost_path,
- config_dir, work_dir, version=(2, 4, 7), conf=None):
+ config_dir, work_dir, version=(2, 4, 7),
+ conf=None,
+ os_info="generic",
+ conf_vhost_path=None):
"""Create an Apache Configurator with the specified options.
:param conf: Function that returns binary paths. self.conf in Configurator
@@ -86,8 +99,8 @@ def get_apache_configurator(
backups = os.path.join(work_dir, "backups")
mock_le_config = mock.MagicMock(
apache_server_root=config_path,
- apache_vhost_root=vhost_path,
- apache_le_vhost_ext=constants.os_constant("le_vhost_ext"),
+ apache_vhost_root=conf_vhost_path,
+ apache_le_vhost_ext="-le-ssl.conf",
apache_challenge_location=config_path,
backup_dir=backups,
config_dir=config_dir,
@@ -95,22 +108,37 @@ def get_apache_configurator(
in_progress_dir=os.path.join(backups, "IN_PROGRESS"),
work_dir=work_dir)
- with mock.patch("certbot_apache.configurator.util.run_script"):
- with mock.patch("certbot_apache.configurator.util."
- "exe_exists") as mock_exe_exists:
- mock_exe_exists.return_value = True
- with mock.patch("certbot_apache.parser.ApacheParser."
- "update_runtime_variables"):
- config = configurator.ApacheConfigurator(
- config=mock_le_config,
- name="apache",
- version=version)
- # This allows testing scripts to set it a bit more quickly
- if conf is not None:
- config.conf = conf # pragma: no cover
+ orig_os_constant = configurator.ApacheConfigurator(mock_le_config,
+ name="apache",
+ version=version).constant
- config.prepare()
+ def mock_os_constant(key, vhost_path=vhost_path):
+ """Mock default vhost path"""
+ if key == "vhost_root":
+ return vhost_path
+ else:
+ return orig_os_constant(key)
+ with mock.patch("certbot_apache.configurator.ApacheConfigurator.constant") as mock_cons:
+ mock_cons.side_effect = mock_os_constant
+ with mock.patch("certbot_apache.configurator.util.run_script"):
+ with mock.patch("certbot_apache.configurator.util."
+ "exe_exists") as mock_exe_exists:
+ mock_exe_exists.return_value = True
+ with mock.patch("certbot_apache.parser.ApacheParser."
+ "update_runtime_variables"):
+ try:
+ config_class = entrypoint.OVERRIDE_CLASSES[os_info]
+ except KeyError:
+ config_class = configurator.ApacheConfigurator
+ config = config_class(config=mock_le_config, name="apache",
+ version=version)
+ # This allows testing scripts to set it a bit more
+ # quickly
+ if conf is not None:
+ config.conf = conf # pragma: no cover
+
+ config.prepare()
return config
diff --git a/certbot-apache/setup.py b/certbot-apache/setup.py
index b276f49f8..8dc283f2d 100644
--- a/certbot-apache/setup.py
+++ b/certbot-apache/setup.py
@@ -63,7 +63,7 @@ setup(
},
entry_points={
'certbot.plugins': [
- 'apache = certbot_apache.configurator:ApacheConfigurator',
+ 'apache = certbot_apache.entrypoint:ENTRYPOINT',
],
},
test_suite='certbot_apache',
diff --git a/certbot-compatibility-test/certbot_compatibility_test/configurators/apache/common.py b/certbot-compatibility-test/certbot_compatibility_test/configurators/apache/common.py
index 2e9e68daf..1d2cfdeca 100644
--- a/certbot-compatibility-test/certbot_compatibility_test/configurators/apache/common.py
+++ b/certbot-compatibility-test/certbot_compatibility_test/configurators/apache/common.py
@@ -9,8 +9,7 @@ import zope.interface
from certbot import configuration
from certbot import errors as le_errors
from certbot import util as certbot_util
-from certbot_apache import configurator
-from certbot_apache import constants
+from certbot_apache import entrypoint
from certbot_compatibility_test import errors
from certbot_compatibility_test import interfaces
from certbot_compatibility_test import util
@@ -56,13 +55,14 @@ class Proxy(configurators_common.Proxy):
def _prepare_configurator(self):
"""Prepares the Apache plugin for testing"""
- for k in constants.CLI_DEFAULTS_DEBIAN.keys():
- setattr(self.le_config, "apache_" + k, constants.os_constant(k))
+ for k in entrypoint.ENTRYPOINT.OS_DEFAULTS.keys():
+ setattr(self.le_config, "apache_" + k,
+ entrypoint.ENTRYPOINT.OS_DEFAULTS[k])
# An alias
self.le_config.apache_handle_modules = self.le_config.apache_handle_mods
- self._configurator = configurator.ApacheConfigurator(
+ self._configurator = entrypoint.ENTRYPOINT(
config=configuration.NamespaceConfig(self.le_config),
name="apache")
self._configurator.prepare()
diff --git a/certbot/util.py b/certbot/util.py
index 30de0c157..b7e60a225 100644
--- a/certbot/util.py
+++ b/certbot/util.py
@@ -342,9 +342,9 @@ def get_os_info_ua(filepath="/etc/os-release"):
"""
if os.path.isfile(filepath):
- os_ua = _get_systemd_os_release_var("PRETTY_NAME", filepath=filepath)
+ os_ua = get_var_from_file("PRETTY_NAME", filepath=filepath)
if not os_ua:
- os_ua = _get_systemd_os_release_var("NAME", filepath=filepath)
+ os_ua = get_var_from_file("NAME", filepath=filepath)
if os_ua:
return os_ua
@@ -361,8 +361,8 @@ def get_systemd_os_info(filepath="/etc/os-release"):
:rtype: `tuple` of `str`
"""
- os_name = _get_systemd_os_release_var("ID", filepath=filepath)
- os_version = _get_systemd_os_release_var("VERSION_ID", filepath=filepath)
+ os_name = get_var_from_file("ID", filepath=filepath)
+ os_version = get_var_from_file("VERSION_ID", filepath=filepath)
return (os_name, os_version)
@@ -377,10 +377,10 @@ def get_systemd_os_like(filepath="/etc/os-release"):
:rtype: `list` of `str`
"""
- return _get_systemd_os_release_var("ID_LIKE", filepath).split(" ")
+ return get_var_from_file("ID_LIKE", filepath).split(" ")
-def _get_systemd_os_release_var(varname, filepath="/etc/os-release"):
+def get_var_from_file(varname, filepath="/etc/os-release"):
"""
Get single value from systemd /etc/os-release
@@ -405,7 +405,7 @@ def _get_systemd_os_release_var(varname, filepath="/etc/os-release"):
def _normalize_string(orig):
"""
- Helper function for _get_systemd_os_release_var() to remove quotes
+ Helper function for get_var_from_file() to remove quotes
and whitespaces
"""
return orig.replace('"', '').replace("'", "").strip()