Set up vhost discovery and overrides for HTTP-01

* Finalized HTTP vhost discovery and added overrides

* Include overrides to every VirtualHost
This commit is contained in:
Joona Hoikkala
2018-01-16 23:08:46 -08:00
committed by Brad Warren
parent 368ca0c109
commit 314c5f19e5
5 changed files with 92 additions and 22 deletions
+13 -1
View File
@@ -436,6 +436,18 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
return True
return False
def find_best_http_vhost(self, target):
"""Returns non-HTTPS vhost objects found from the Apache config
:param str target: Domain name of the desired VirtualHost
:returns: VirtualHost object that's the best match for target name
:rtype: `obj.VirtualHost` or None
"""
nonssl_vhosts = [i for i in self.vhosts if not i.ssl]
return self._find_best_vhost(target, nonssl_vhosts)
def _find_best_vhost(self, target_name, vhosts=None):
"""Finds the best vhost for a target_name.
@@ -508,7 +520,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
virtual host addresses
:rtype: set
"""
"""
all_names = set()
vhost_macro = []
+42 -18
View File
@@ -7,26 +7,38 @@ from certbot.plugins import common
logger = logging.getLogger(__name__)
class ApacheHttp01(common.TLSSNI01):
"""Class that performs HTPP-01 challenges within the Apache configurator."""
"""Class that performs HTTP-01 challenges within the Apache configurator."""
CONFIG_TEMPLATE24 = """\
Alias /.well-known/acme-challenge {0}
CONFIG_TEMPLATE_COMMON = """\
Alias /.well-known/acme-challenge {0}"
<Directory {0} >
Require all granted
</Directory>
"""
<IfModule mod_proxy.c>
ProxyPass "/.well-known/acme-challenge" !
</IfModule>
"""
CONFIG_TEMPLATE22 = """\
Alias /.well-known/acme-challenge {0}
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteRule /.well-known/acme-challenge/(.*) {0}/$1 [L,S=9999]
</IfModule>
<Directory {0} >
Order allow,deny
Allow from all
</Directory>
<Directory {0}>
Order allow deny
Allow from all
</Directory>
"""
"""
CONFIG_TEMPLATE24 = """\
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteRule /.well-known/acme-challenge/(.*) {0}/$1 [END]
</IfModule>
<Directory {0}>
Require all granted
</Directory>
"""
def __init__(self, *args, **kwargs):
super(ApacheHttp01, self).__init__(*args, **kwargs)
@@ -50,6 +62,7 @@ Alias /.well-known/acme-challenge {0}
self.prepare_http01_modules()
responses = self._set_up_challenges()
self._mod_config()
# Save reversible changes
self.configurator.save("HTTP Challenge", True)
@@ -70,21 +83,26 @@ Alias /.well-known/acme-challenge {0}
self.configurator.enable_mod(mod, temp=True)
def _mod_config(self):
self.configurator.parser.add_include(
self.configurator.parser.loc["default"], self.challenge_conf)
for chall in self.achalls:
vh = self.configurator.find_best_http_vhost(chall.domain)
if vh:
self._set_up_include_directive(vh)
self.configurator.reverter.register_file_creation(
True, self.challenge_conf)
if self.configurator.version < (2, 4):
config_template = self.CONFIG_TEMPLATE22
config_template = self.CONFIG_TEMPLATE_COMMON + self.CONFIG_TEMPLATE22
else:
config_template = self.CONFIG_TEMPLATE24
config_template = self.CONFIG_TEMPLATE_COMMON + self.CONFIG_TEMPLATE24
config_text = config_template.format(self.challenge_dir)
logger.debug("writing a config file with text:\n %s", config_text)
with open(self.challenge_conf, "w") as new_conf:
new_conf.write(config_text)
def _set_up_challenges(self):
if not os.path.isdir(self.challenge_dir):
os.makedirs(self.challenge_dir)
@@ -107,3 +125,9 @@ Alias /.well-known/acme-challenge {0}
os.chmod(name, 0o644)
return response
def _set_up_include_directive(self, vhost):
"""Includes override configuration to the beginning of VirtualHost.
Note that this include isn't added to Augeas search tree"""
self.configurator.parser.add_dir_beginning(vhost.path, "Include",
self.challenge_conf)
+17
View File
@@ -332,6 +332,23 @@ class ApacheParser(object):
else:
self.aug.set(aug_conf_path + "/directive[last()]/arg", args)
def add_dir_beginning(self, aug_conf_path, dirname, args):
"""Adds the directive to the beginning of defined aug_conf_path.
:param str aug_conf_path: Augeas configuration path to add directive
:param str dirname: Directive to add
:param args: Value of the directive. ie. Listen 443, 443 is arg
:type args: list or str
"""
first_dir = aug_conf_path + "/directive[1]"
self.aug.insert(first_dir, "directive", True)
self.aug.set(first_dir, dirname)
if isinstance(args, list):
for i, value in enumerate(args, 1):
self.aug.set(first_dir + "/arg[%d]" % (i), value)
else:
self.aug.set(first_dir + "/arg", args)
def find_dir(self, directive, arg=None, start=None, exclude=True):
"""Finds directive in the configuration.
@@ -119,9 +119,9 @@ class ApacheHttp01Test(util.ApacheTest):
self.assertTrue(os.path.exists(challenge_dir))
def _test_challenge_conf(self):
self.assertEqual(
len(self.config.parser.find_dir(
"Include", self.http.challenge_conf)), 1)
#self.assertEqual(
# len(self.config.parser.find_dir(
# "Include", self.http.challenge_conf)), 1)
with open(self.http.challenge_conf) as f:
conf_contents = f.read()
@@ -66,6 +66,23 @@ class BasicParserTest(util.ParserTest):
for i, match in enumerate(matches):
self.assertEqual(self.parser.aug.get(match), str(i + 1))
def test_add_dir_beginning(self):
aug_default = "/files" + self.parser.loc["default"]
self.parser.add_dir_beginning(aug_default,
"AddDirectiveBeginning",
"testBegin")
self.assertTrue(
self.parser.find_dir("AddDirectiveBeginning", "testBegin", aug_default))
self.assertEqual(
self.parser.aug.get(aug_default+"/directive[1]"),
"AddDirectiveBeginning")
self.parser.add_dir_beginning(aug_default, "AddList", ["1", "2", "3", "4"])
matches = self.parser.find_dir("AddList", None, aug_default)
for i, match in enumerate(matches):
self.assertEqual(self.parser.aug.get(match), str(i + 1))
def test_empty_arg(self):
self.assertEquals(None,
self.parser.get_arg("/files/whatever/nonexistent"))