Compare commits

...

24 Commits

Author SHA1 Message Date
Erica Portnoy
2f05226213 one more tuple 2018-02-28 21:58:51 -08:00
Erica Portnoy
8153c987f4 make vhost hashable 2018-02-28 21:55:26 -08:00
Erica Portnoy
c1da1f53d5 lint 2018-02-28 21:51:09 -08:00
Erica Portnoy
2934da5a5a [^.]+ 2018-02-28 21:44:22 -08:00
Erica Portnoy
38b2c8b251 don't filter by domain 2018-02-28 21:38:21 -08:00
Erica Portnoy
31ce670c31 lint 2018-02-28 21:31:54 -08:00
Erica Portnoy
298809a860 filter wildcard vhosts by port 2018-02-28 21:27:58 -08:00
Erica Portnoy
346e320f4e remove extra newline 2018-02-28 21:02:54 -08:00
Erica Portnoy
82b93ff8cc take selecting vhosts out of loop 2018-02-28 20:59:55 -08:00
Erica Portnoy
8ddec361f5 remove _wildcard_domain 2018-02-28 20:52:55 -08:00
Erica Portnoy
c80595dc5c change message to be generic to installation and enhancement 2018-02-28 20:46:10 -08:00
Erica Portnoy
f9f2f9466d lint 2018-02-28 20:40:31 -08:00
Erica Portnoy
9db971e218 add configurator tests 2018-02-28 20:39:37 -08:00
Erica Portnoy
b98e603d95 start adding tests and lint errors 2018-02-28 19:27:13 -08:00
Erica Portnoy
11cb3afa7e functional code 2018-02-28 19:17:45 -08:00
Erica Portnoy
11f71cb5be match redirects properly 2018-02-28 13:07:48 -08:00
Erica Portnoy
4436fd6b34 Merge branch 'master' into nginx-acmev2 2018-02-28 12:38:42 -08:00
Erica Portnoy
7294447c47 say server block 2018-02-23 17:37:54 -08:00
Erica Portnoy
555f43f9e1 update display_ops_test and errors found 2018-02-23 17:36:21 -08:00
Erica Portnoy
228f57a0a9 add display_ops and display_repr 2018-02-23 17:29:33 -08:00
Erica Portnoy
ec159ef72e update tests 2018-02-23 17:23:53 -08:00
Erica Portnoy
dc98b03bee redirect enhance and some tests 2018-02-23 17:20:19 -08:00
Erica Portnoy
a934ddee86 support wildcards for enhance 2018-02-23 16:58:55 -08:00
Erica Portnoy
fce6accc18 support wildcards for deploy_cert 2018-02-23 16:35:36 -08:00
8 changed files with 370 additions and 52 deletions

View File

@@ -23,6 +23,7 @@ from certbot import util
from certbot.plugins import common
from certbot_nginx import constants
from certbot_nginx import display_ops
from certbot_nginx import nginxparser
from certbot_nginx import parser
from certbot_nginx import tls_sni_01
@@ -92,6 +93,11 @@ class NginxConfigurator(common.Installer):
# For creating new vhosts if no names match
self.new_vhost = None
# List of vhosts configured per wildcard domain on this run.
# used by deploy_cert() and enhance()
self._wildcard_vhosts = {}
self._wildcard_redirect_vhosts = {}
# Add number of outstanding challenges
self._chall_out = 0
@@ -146,6 +152,7 @@ class NginxConfigurator(common.Installer):
raise errors.PluginError(
'Unable to lock %s', self.conf('server-root'))
# Entry point in main.py for installing cert
def deploy_cert(self, domain, cert_path, key_path,
chain_path=None, fullchain_path=None):
@@ -166,14 +173,24 @@ class NginxConfigurator(common.Installer):
"The nginx plugin currently requires --fullchain-path to "
"install a cert.")
vhost = self.choose_vhost(domain, create_if_no_match=True)
vhosts = self.choose_vhosts(domain, create_if_no_match=True)
for vhost in vhosts:
self._deploy_cert(vhost, cert_path, key_path, chain_path, fullchain_path)
def _deploy_cert(self, vhost, cert_path, key_path, chain_path, fullchain_path):
# pylint: disable=unused-argument
"""
Helper function for deploy_cert() that handles the actual deployment
this exists because we might want to do multiple deployments per
domain originally passed for deploy_cert(). This is especially true
with wildcard certificates
"""
cert_directives = [['\n ', 'ssl_certificate', ' ', fullchain_path],
['\n ', 'ssl_certificate_key', ' ', key_path]]
self.parser.add_server_directives(vhost,
cert_directives, replace=True)
logger.info("Deployed Certificate to VirtualHost %s for %s",
vhost.filep, ", ".join(vhost.names))
logger.info("Deploying Certificate to VirtualHost %s", vhost.filep)
self.save_notes += ("Changed vhost at %s with addresses of %s\n" %
(vhost.filep,
@@ -181,10 +198,61 @@ class NginxConfigurator(common.Installer):
self.save_notes += "\tssl_certificate %s\n" % fullchain_path
self.save_notes += "\tssl_certificate_key %s\n" % key_path
def _choose_vhosts_wildcard(self, domain, prefer_ssl, no_ssl_filter_port=None):
"""Prompts user to choose vhosts to install a wildcard certificate for"""
if prefer_ssl:
vhosts_cache = self._wildcard_vhosts
preference_test = lambda x: x.ssl
else:
vhosts_cache = self._wildcard_redirect_vhosts
preference_test = lambda x: not x.ssl
# Caching!
if domain in vhosts_cache:
# Vhosts for a wildcard domain were already selected
return vhosts_cache[domain]
# Get all vhosts whether or not they are covered by the wildcard domain
vhosts = self.parser.get_vhosts()
# Go through the vhosts, making sure that we cover all the names
# present, but preferring the SSL or non-SSL vhosts
filtered_vhosts = {}
for vhost in vhosts:
# Ensure we're listening non-sslishly on no_ssl_filter_port
if no_ssl_filter_port is not None:
if not self._vhost_listening_on_port_no_ssl(vhost, no_ssl_filter_port):
continue
for name in vhost.names:
if preference_test(vhost):
# Prefer either SSL or non-SSL vhosts
filtered_vhosts[name] = vhost
elif name not in filtered_vhosts:
# Add if not in list previously
filtered_vhosts[name] = vhost
# Only unique VHost objects
dialog_input = set([vhost for vhost in filtered_vhosts.values()])
# Ask the user which of names to enable, expect list of names back
return_vhosts = display_ops.select_vhost_multiple(list(dialog_input))
for vhost in return_vhosts:
if domain not in vhosts_cache:
vhosts_cache[domain] = []
vhosts_cache[domain].append(vhost)
return return_vhosts
#######################
# Vhost parsing methods
#######################
def choose_vhost(self, target_name, create_if_no_match=False):
def _choose_vhost_single(self, target_name):
matches = self._get_ranked_matches(target_name)
vhosts = [x for x in [self._select_best_name_match(matches)] if x is not None]
return vhosts
def choose_vhosts(self, target_name, create_if_no_match=False):
"""Chooses a virtual host based on the given domain name.
.. note:: This makes the vhost SSL-enabled if it isn't already. Follows
@@ -202,17 +270,19 @@ class NginxConfigurator(common.Installer):
when there is no match found. If we can't choose a default, raise a
MisconfigurationError.
:returns: ssl vhost associated with name
:rtype: :class:`~certbot_nginx.obj.VirtualHost`
:returns: ssl vhosts associated with name
:rtype: list of :class:`~certbot_nginx.obj.VirtualHost`
"""
vhost = None
matches = self._get_ranked_matches(target_name)
vhost = self._select_best_name_match(matches)
if not vhost:
if util.is_wildcard_domain(target_name):
# Ask user which VHosts to support.
vhosts = self._choose_vhosts_wildcard(target_name, prefer_ssl=True)
else:
vhosts = self._choose_vhost_single(target_name)
if not vhosts:
if create_if_no_match:
vhost = self._vhost_from_duplicated_default(target_name)
# result will not be [None] because it errors on failure
vhosts = [self._vhost_from_duplicated_default(target_name)]
else:
# No matches. Raise a misconfiguration error.
raise errors.MisconfigurationError(
@@ -222,10 +292,11 @@ class NginxConfigurator(common.Installer):
"nginx configuration: "
"https://nginx.org/en/docs/http/server_names.html") % (target_name))
# Note: if we are enhancing with ocsp, vhost should already be ssl.
if not vhost.ssl:
self._make_server_ssl(vhost)
for vhost in vhosts:
if not vhost.ssl:
self._make_server_ssl(vhost)
return vhost
return vhosts
def ipv6_info(self, port):
"""Returns tuple of booleans (ipv6_active, ipv6only_present)
@@ -359,7 +430,7 @@ class NginxConfigurator(common.Installer):
return sorted(matches, key=lambda x: x['rank'])
def choose_redirect_vhost(self, target_name, port, create_if_no_match=False):
def choose_redirect_vhosts(self, target_name, port, create_if_no_match=False):
"""Chooses a single virtual host for redirect enhancement.
Chooses the vhost most closely matching target_name that is
@@ -377,15 +448,20 @@ class NginxConfigurator(common.Installer):
when there is no match found. If we can't choose a default, raise a
MisconfigurationError.
:returns: vhost associated with name
:rtype: :class:`~certbot_nginx.obj.VirtualHost`
:returns: vhosts associated with name
:rtype: list of :class:`~certbot_nginx.obj.VirtualHost`
"""
matches = self._get_redirect_ranked_matches(target_name, port)
vhost = self._select_best_name_match(matches)
if not vhost and create_if_no_match:
vhost = self._vhost_from_duplicated_default(target_name, port=port)
return vhost
if util.is_wildcard_domain(target_name):
# Ask user which VHosts to enhance.
vhosts = self._choose_vhosts_wildcard(target_name, prefer_ssl=False,
no_ssl_filter_port=port)
else:
matches = self._get_redirect_ranked_matches(target_name, port)
vhosts = [x for x in [self._select_best_name_match(matches)]if x is not None]
if not vhosts and create_if_no_match:
vhosts = [self._vhost_from_duplicated_default(target_name, port=port)]
return vhosts
def _port_matches(self, test_port, matching_port):
# test_port is a number, matching is a number or "" or None
@@ -395,6 +471,23 @@ class NginxConfigurator(common.Installer):
else:
return test_port == matching_port
def _vhost_listening_on_port_no_ssl(self, vhost, port):
found_matching_port = False
if len(vhost.addrs) == 0:
# if there are no listen directives at all, Nginx defaults to
# listening on port 80.
found_matching_port = (port == self.DEFAULT_LISTEN_PORT)
else:
for addr in vhost.addrs:
if self._port_matches(port, addr.get_port()) and addr.ssl == False:
found_matching_port = True
if found_matching_port:
# make sure we don't have an 'ssl on' directive
return not self.parser.has_ssl_on_directive(vhost)
else:
return False
def _get_redirect_ranked_matches(self, target_name, port):
"""Gets a ranked list of plaintextish port-listening vhosts matching target_name
@@ -411,21 +504,7 @@ class NginxConfigurator(common.Installer):
all_vhosts = self.parser.get_vhosts()
def _vhost_matches(vhost, port):
found_matching_port = False
if len(vhost.addrs) == 0:
# if there are no listen directives at all, Nginx defaults to
# listening on port 80.
found_matching_port = (port == self.DEFAULT_LISTEN_PORT)
else:
for addr in vhost.addrs:
if self._port_matches(port, addr.get_port()) and addr.ssl == False:
found_matching_port = True
if found_matching_port:
# make sure we don't have an 'ssl on' directive
return not self.parser.has_ssl_on_directive(vhost)
else:
return False
return self._vhost_listening_on_port_no_ssl(vhost, port)
matching_vhosts = [vhost for vhost in all_vhosts if _vhost_matches(vhost, port)]
@@ -587,17 +666,31 @@ class NginxConfigurator(common.Installer):
"""
port = self.DEFAULT_LISTEN_PORT
vhost = None
# If there are blocks listening plaintextishly on self.DEFAULT_LISTEN_PORT,
# choose the most name-matching one.
vhost = self.choose_redirect_vhost(domain, port)
vhosts = self.choose_redirect_vhosts(domain, port)
if vhost is None:
if not vhosts:
logger.info("No matching insecure server blocks listening on port %s found.",
self.DEFAULT_LISTEN_PORT)
return
for vhost in vhosts:
self._enable_redirect_single(domain, vhost)
def _enable_redirect_single(self, domain, vhost):
"""Redirect all equivalent HTTP traffic to ssl_vhost.
If the vhost is listening plaintextishly, separate out the
relevant directives into a new server block and add a rewrite directive.
.. note:: This function saves the configuration
:param str domain: domain to enable redirect for
:param `~obj.Vhost` vhost: vhost to enable redirect for
"""
new_vhost = None
if vhost.ssl:
new_vhost = self.parser.duplicate_vhost(vhost,
@@ -638,7 +731,18 @@ class NginxConfigurator(common.Installer):
:type chain_path: `str` or `None`
"""
vhost = self.choose_vhost(domain)
vhosts = self.choose_vhosts(domain)
for vhost in vhosts:
self._enable_ocsp_stapling_single(vhost, chain_path)
def _enable_ocsp_stapling_single(self, vhost, chain_path):
"""Include OCSP response in TLS handshake
:param str vhost: vhost to enable OCSP response for
:param chain_path: chain file path
:type chain_path: `str` or `None`
"""
if self.version < (1, 3, 7):
raise errors.PluginError("Version 1.3.7 or greater of nginx "
"is needed to enable OCSP stapling")
@@ -889,14 +993,23 @@ def _test_block_from_block(block):
parser.comment_directive(test_block, 0)
return test_block[:-1]
def _redirect_block_for_domain(domain):
updated_domain = domain
match_symbol = '='
if util.is_wildcard_domain(domain):
match_symbol = '~'
updated_domain = updated_domain.replace('.', r'\.')
updated_domain = updated_domain.replace('*', '[^.]+')
updated_domain = '^' + updated_domain + '$'
redirect_block = [[
['\n ', 'if', ' ', '($host', ' ', '=', ' ', '%s)' % domain, ' '],
['\n ', 'if', ' ', '($host', ' ', match_symbol, ' ', '%s)' % updated_domain, ' '],
[['\n ', 'return', ' ', '301', ' ', 'https://$host$request_uri'],
'\n ']],
['\n']]
return redirect_block
def nginx_restart(nginx_ctl, nginx_conf):
"""Restarts the Nginx Server.

View File

@@ -0,0 +1,44 @@
"""Contains UI methods for Nginx operations."""
import logging
import zope.component
from certbot import interfaces
import certbot.display.util as display_util
logger = logging.getLogger(__name__)
def select_vhost_multiple(vhosts):
"""Select multiple Vhosts to install the certificate for
:param vhosts: Available Nginx VirtualHosts
:type vhosts: :class:`list` of type `~obj.Vhost`
:returns: List of VirtualHosts
:rtype: :class:`list`of type `~obj.Vhost`
"""
if not vhosts:
return list()
tags_list = [vhost.display_repr()+"\n" for vhost in vhosts]
# Remove the extra newline from the last entry
if len(tags_list):
tags_list[-1] = tags_list[-1][:-1]
code, names = zope.component.getUtility(interfaces.IDisplay).checklist(
"Which server blocks would you like to modify?",
tags=tags_list, force_interactive=True)
if code == display_util.OK:
return_vhosts = _reversemap_vhosts(names, vhosts)
return return_vhosts
return []
def _reversemap_vhosts(names, vhosts):
"""Helper function for select_vhost_multiple for mapping string
representations back to actual vhost objects"""
return_vhosts = list()
for selection in names:
for vhost in vhosts:
if vhost.display_repr().strip() == selection.strip():
return_vhosts.append(vhost)
return return_vhosts

View File

@@ -179,13 +179,17 @@ class NginxHttp01(common.ChallengePerformer):
"""
try:
vhost = self.configurator.choose_redirect_vhost(achall.domain,
vhosts = self.configurator.choose_redirect_vhosts(achall.domain,
'%i' % self.configurator.config.http01_port, create_if_no_match=True)
except errors.MisconfigurationError:
# Couldn't find either a matching name+port server block
# or a port+default_server block, so create a dummy block
return self._make_server_block(achall)
# len is max 1 because Nginx doesn't authenticate wildcards
# if len were or vhosts None, we would have errored
vhost = vhosts[0]
# Modify existing server block
validation = achall.validation(achall.account_key)
validation_path = self._get_validation_path(achall)

View File

@@ -193,6 +193,11 @@ class VirtualHost(object): # pylint: disable=too-few-public-methods
return False
def __hash__(self):
return hash((self.filep, tuple(self.path),
tuple(self.addrs), tuple(self.names),
self.ssl, self.enabled))
def contains_list(self, test):
"""Determine if raw server block contains test list at top level
"""
@@ -216,3 +221,15 @@ class VirtualHost(object): # pylint: disable=too-few-public-methods
for a in self.addrs:
if not a.ipv6:
return True
def display_repr(self):
"""Return a representation of VHost to be used in dialog"""
return (
"File: {filename}\n"
"Addresses: {addrs}\n"
"Names: {names}\n"
"HTTPS: {https}\n".format(
filename=self.filep,
addrs=", ".join(str(addr) for addr in self.addrs),
names=", ".join(self.names),
https="Yes" if self.ssl else "No"))

View File

@@ -128,7 +128,7 @@ class NginxConfiguratorTest(util.NginxTest):
['#', parser.COMMENT]]]],
parsed[0])
def test_choose_vhost(self):
def test_choose_vhosts(self):
localhost_conf = set(['localhost', r'~^(www\.)?(example|bar)\.'])
server_conf = set(['somename', 'another.alias', 'alias'])
example_conf = set(['.example.com', 'example.*'])
@@ -159,7 +159,7 @@ class NginxConfiguratorTest(util.NginxTest):
'69.255.225.155']
for name in results:
vhost = self.config.choose_vhost(name)
vhost = self.config.choose_vhosts(name)[0]
path = os.path.relpath(vhost.filep, self.temp_dir)
self.assertEqual(results[name], vhost.names)
@@ -173,7 +173,7 @@ class NginxConfiguratorTest(util.NginxTest):
for name in bad_results:
self.assertRaises(errors.MisconfigurationError,
self.config.choose_vhost, name)
self.config.choose_vhosts, name)
def test_ipv6only(self):
# ipv6_info: (ipv6_active, ipv6only_present)
@@ -702,6 +702,100 @@ class NginxConfiguratorTest(util.NginxTest):
self.config.rollback_checkpoints()
self.assertTrue(mock_parser_load.call_count == 3)
def test_choose_vhosts_wildcard(self):
# pylint: disable=protected-access
mock_path = "certbot_nginx.display_ops.select_vhost_multiple"
with mock.patch(mock_path) as mock_select_vhs:
vhost = [x for x in self.config.parser.get_vhosts()
if 'summer.com' in x.names][0]
mock_select_vhs.return_value = [vhost]
vhs = self.config._choose_vhosts_wildcard("*.com",
prefer_ssl=True)
# Check that the dialog was called with migration.com
self.assertTrue(vhost in mock_select_vhs.call_args[0][0])
# And the actual returned values
self.assertEquals(len(vhs), 1)
self.assertEqual(vhs[0], vhost)
def test_choose_vhosts_wildcard_redirect(self):
# pylint: disable=protected-access
mock_path = "certbot_nginx.display_ops.select_vhost_multiple"
with mock.patch(mock_path) as mock_select_vhs:
vhost = [x for x in self.config.parser.get_vhosts()
if 'summer.com' in x.names][0]
mock_select_vhs.return_value = [vhost]
vhs = self.config._choose_vhosts_wildcard("*.com",
prefer_ssl=False)
# Check that the dialog was called with migration.com
self.assertTrue(vhost in mock_select_vhs.call_args[0][0])
# And the actual returned values
self.assertEquals(len(vhs), 1)
self.assertEqual(vhs[0], vhost)
def test_deploy_cert_wildcard(self):
# pylint: disable=protected-access
mock_choose_vhosts = mock.MagicMock()
vhost = [x for x in self.config.parser.get_vhosts()
if 'geese.com' in x.names][0]
mock_choose_vhosts.return_value = [vhost]
self.config._choose_vhosts_wildcard = mock_choose_vhosts
mock_d = "certbot_nginx.configurator.NginxConfigurator._deploy_cert"
with mock.patch(mock_d) as mock_dep:
self.config.deploy_cert("*.com", "/tmp/path",
"/tmp/path", "/tmp/path", "/tmp/path")
self.assertTrue(mock_dep.called)
self.assertEquals(len(mock_dep.call_args_list), 1)
self.assertEqual(vhost, mock_dep.call_args_list[0][0][0])
@mock.patch("certbot_nginx.display_ops.select_vhost_multiple")
def test_deploy_cert_wildcard_no_vhosts(self, mock_dialog):
# pylint: disable=protected-access
mock_dialog.return_value = []
self.assertRaises(errors.PluginError,
self.config.deploy_cert,
"*.wild.cat", "/tmp/path", "/tmp/path",
"/tmp/path", "/tmp/path")
@mock.patch("certbot_nginx.display_ops.select_vhost_multiple")
def test_enhance_wildcard_ocsp_after_install(self, mock_dialog):
# pylint: disable=protected-access
vhost = [x for x in self.config.parser.get_vhosts()
if 'geese.com' in x.names][0]
self.config._wildcard_vhosts["*.com"] = [vhost]
self.config.enhance("*.com", "staple-ocsp", "example/chain.pem")
self.assertFalse(mock_dialog.called)
@mock.patch("certbot_nginx.display_ops.select_vhost_multiple")
def test_enhance_wildcard_redirect_or_ocsp_no_install(self, mock_dialog):
vhost = [x for x in self.config.parser.get_vhosts()
if 'summer.com' in x.names][0]
mock_dialog.return_value = [vhost]
self.config.enhance("*.com", "staple-ocsp", "example/chain.pem")
self.assertTrue(mock_dialog.called)
@mock.patch("certbot_nginx.display_ops.select_vhost_multiple")
def test_enhance_wildcard_double_redirect(self, mock_dialog):
# pylint: disable=protected-access
vhost = [x for x in self.config.parser.get_vhosts()
if 'summer.com' in x.names][0]
self.config._wildcard_redirect_vhosts["*.com"] = [vhost]
self.config.enhance("*.com", "redirect")
self.assertFalse(mock_dialog.called)
def test_choose_vhosts_wildcard_no_ssl_filter_port(self):
# pylint: disable=protected-access
mock_path = "certbot_nginx.display_ops.select_vhost_multiple"
with mock.patch(mock_path) as mock_select_vhs:
mock_select_vhs.return_value = []
self.config._choose_vhosts_wildcard("*.com",
prefer_ssl=False,
no_ssl_filter_port='80')
# Check that the dialog was called with only port 80 vhosts
self.assertEqual(len(mock_select_vhs.call_args[0][0]), 4)
class InstallSslOptionsConfTest(util.NginxTest):
"""Test that the options-ssl-nginx.conf file is installed and updated properly."""

View File

@@ -0,0 +1,45 @@
"""Test certbot_apache.display_ops."""
import unittest
from certbot.display import util as display_util
from certbot.tests import util as certbot_util
from certbot_nginx import parser
from certbot_nginx.display_ops import select_vhost_multiple
from certbot_nginx.tests import util
class SelectVhostMultiTest(util.NginxTest):
"""Tests for certbot_nginx.display_ops.select_vhost_multiple."""
def setUp(self):
super(SelectVhostMultiTest, self).setUp()
nparser = parser.NginxParser(self.config_path)
self.vhosts = nparser.get_vhosts()
def test_select_no_input(self):
self.assertFalse(select_vhost_multiple([]))
@certbot_util.patch_get_utility()
def test_select_correct(self, mock_util):
mock_util().checklist.return_value = (
display_util.OK, [self.vhosts[3].display_repr(),
self.vhosts[2].display_repr()])
vhs = select_vhost_multiple([self.vhosts[3],
self.vhosts[2],
self.vhosts[1]])
self.assertTrue(self.vhosts[2] in vhs)
self.assertTrue(self.vhosts[3] in vhs)
self.assertFalse(self.vhosts[1] in vhs)
@certbot_util.patch_get_utility()
def test_select_cancel(self, mock_util):
mock_util().checklist.return_value = (display_util.CANCEL, "whatever")
vhs = select_vhost_multiple([self.vhosts[2], self.vhosts[3]])
self.assertFalse(vhs)
if __name__ == "__main__":
unittest.main() # pragma: no cover

View File

@@ -61,10 +61,10 @@ class TlsSniPerformTest(util.NginxTest):
shutil.rmtree(self.work_dir)
@mock.patch("certbot_nginx.configurator"
".NginxConfigurator.choose_vhost")
".NginxConfigurator.choose_vhosts")
def test_perform(self, mock_choose):
self.sni.add_chall(self.achalls[1])
mock_choose.return_value = None
mock_choose.return_value = []
result = self.sni.perform()
self.assertFalse(result is None)

View File

@@ -55,10 +55,11 @@ class NginxTlsSni01(common.TLSSNI01):
self.configurator.config.tls_sni_01_port)
for achall in self.achalls:
vhost = self.configurator.choose_vhost(achall.domain, create_if_no_match=True)
vhosts = self.configurator.choose_vhosts(achall.domain, create_if_no_match=True)
if vhost is not None and vhost.addrs:
addresses.append(list(vhost.addrs))
# len is max 1 because Nginx doesn't authenticate wildcards
if vhosts and vhosts[0].addrs:
addresses.append(list(vhosts[0].addrs))
else:
if ipv6:
# If IPv6 is active in Nginx configuration