Compare commits
24 Commits
update-dev
...
nginx-acme
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2f05226213 | ||
|
|
8153c987f4 | ||
|
|
c1da1f53d5 | ||
|
|
2934da5a5a | ||
|
|
38b2c8b251 | ||
|
|
31ce670c31 | ||
|
|
298809a860 | ||
|
|
346e320f4e | ||
|
|
82b93ff8cc | ||
|
|
8ddec361f5 | ||
|
|
c80595dc5c | ||
|
|
f9f2f9466d | ||
|
|
9db971e218 | ||
|
|
b98e603d95 | ||
|
|
11cb3afa7e | ||
|
|
11f71cb5be | ||
|
|
4436fd6b34 | ||
|
|
7294447c47 | ||
|
|
555f43f9e1 | ||
|
|
228f57a0a9 | ||
|
|
ec159ef72e | ||
|
|
dc98b03bee | ||
|
|
a934ddee86 | ||
|
|
fce6accc18 |
@@ -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.
|
||||
|
||||
|
||||
44
certbot-nginx/certbot_nginx/display_ops.py
Normal file
44
certbot-nginx/certbot_nginx/display_ops.py
Normal 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
|
||||
@@ -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)
|
||||
|
||||
@@ -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"))
|
||||
|
||||
@@ -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."""
|
||||
|
||||
|
||||
45
certbot-nginx/certbot_nginx/tests/display_ops_test.py
Normal file
45
certbot-nginx/certbot_nginx/tests/display_ops_test.py
Normal 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
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user