mirror of
https://github.com/certbot/certbot.git
synced 2026-07-30 18:04:31 +02:00
Add nginx server block for target_name if one doesn't exist
This commit is contained in:
@@ -159,8 +159,12 @@ class NginxConfigurator(object):
|
|||||||
|
|
||||||
matches = self._get_ranked_matches(target_name)
|
matches = self._get_ranked_matches(target_name)
|
||||||
if not matches:
|
if not matches:
|
||||||
# No matches at all :'(
|
# No matches. Create a new vhost with this name in nginx.conf.
|
||||||
pass
|
filep = self.parser.loc["root"]
|
||||||
|
new_block = [['server'], [['server_name', target_name]]]
|
||||||
|
self.parser.add_http_directives(filep, new_block)
|
||||||
|
vhost = obj.VirtualHost(filep, set([]), False, True,
|
||||||
|
set([target_name]), list(new_block[1]))
|
||||||
elif matches[0]['rank'] in xrange(2, 6):
|
elif matches[0]['rank'] in xrange(2, 6):
|
||||||
# Wildcard match - need to find the longest one
|
# Wildcard match - need to find the longest one
|
||||||
rank = matches[0]['rank']
|
rank = matches[0]['rank']
|
||||||
|
|||||||
@@ -52,9 +52,8 @@ class NginxDvsni(ApacheDvsni):
|
|||||||
vhost = self.configurator.choose_vhost(achall.domain)
|
vhost = self.configurator.choose_vhost(achall.domain)
|
||||||
if vhost is None:
|
if vhost is None:
|
||||||
logging.error(
|
logging.error(
|
||||||
"No nginx vhost exists with server_name or alias of: %s",
|
"No nginx vhost exists with server_name matching: %s",
|
||||||
achall.domain)
|
achall.domain)
|
||||||
logging.error("No default 443 nginx vhost exists")
|
|
||||||
logging.error("Please specify server_names in the Nginx config")
|
logging.error("Please specify server_names in the Nginx config")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ class VirtualHost(object): # pylint: disable=too-few-public-methods
|
|||||||
:ivar set addrs: Virtual Host addresses (:class:`set` of :class:`Addr`)
|
:ivar set addrs: Virtual Host addresses (:class:`set` of :class:`Addr`)
|
||||||
:ivar set names: Server names/aliases of vhost
|
:ivar set names: Server names/aliases of vhost
|
||||||
(:class:`list` of :class:`str`)
|
(:class:`list` of :class:`str`)
|
||||||
:ivar array raw: The raw form of the parsed server block
|
:ivar list raw: The raw form of the parsed server block
|
||||||
|
|
||||||
:ivar bool ssl: SSLEngine on in vhost
|
:ivar bool ssl: SSLEngine on in vhost
|
||||||
:ivar bool enabled: Virtual host is enabled
|
:ivar bool enabled: Virtual host is enabled
|
||||||
|
|||||||
@@ -253,7 +253,7 @@ class NginxParser(object):
|
|||||||
|
|
||||||
def add_server_directives(self, filename, names, directives,
|
def add_server_directives(self, filename, names, directives,
|
||||||
replace=False):
|
replace=False):
|
||||||
"""Add or replace directives in server blocks identified by server_name.
|
"""Add or replace directives in the first server block with names.
|
||||||
|
|
||||||
..note :: If replace is True, this raises a misconfiguration error
|
..note :: If replace is True, this raises a misconfiguration error
|
||||||
if the directive does not already exist.
|
if the directive does not already exist.
|
||||||
@@ -267,14 +267,20 @@ class NginxParser(object):
|
|||||||
:param bool replace: Whether to only replace existing directives
|
:param bool replace: Whether to only replace existing directives
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if replace:
|
_do_for_subarray(self.parsed[filename],
|
||||||
_do_for_subarray(self.parsed[filename],
|
lambda x: self._has_server_names(x, names),
|
||||||
lambda x: self._has_server_names(x, names),
|
lambda x: _add_directives(x, directives, replace))
|
||||||
lambda x: _replace_directives(x, directives))
|
|
||||||
else:
|
def add_http_directives(self, filename, directives):
|
||||||
_do_for_subarray(self.parsed[filename],
|
"""Adds directives to the first encountered HTTP block in filename.
|
||||||
lambda x: self._has_server_names(x, names),
|
|
||||||
lambda x: x.extend(directives))
|
:param str filename: The absolute filename of the config file
|
||||||
|
:param list directives: The directives to add
|
||||||
|
|
||||||
|
"""
|
||||||
|
_do_for_subarray(self.parsed[filename],
|
||||||
|
lambda x: x[0] == ['http'],
|
||||||
|
lambda x: _add_directives(x[1], [directives], False))
|
||||||
|
|
||||||
def get_all_certs_keys(self):
|
def get_all_certs_keys(self):
|
||||||
"""Gets all certs and keys in the nginx config.
|
"""Gets all certs and keys in the nginx config.
|
||||||
@@ -463,24 +469,28 @@ def _parse_server(server):
|
|||||||
return parsed_server
|
return parsed_server
|
||||||
|
|
||||||
|
|
||||||
def _replace_directives(block, directives):
|
def _add_directives(block, directives, replace=False):
|
||||||
"""Replaces directives in a block. If the directive doesn't exist in
|
"""Adds or replaces directives in a block. If the directive doesn't exist in
|
||||||
the entry already, raises a misconfiguration error.
|
the entry already, raises a misconfiguration error.
|
||||||
|
|
||||||
..todo :: Find directives that are in included files.
|
..todo :: Find directives that are in included files.
|
||||||
|
|
||||||
:param list block: The block to replace in
|
:param list block: The block to replace in
|
||||||
:param list directives: The new directives.
|
:param list directives: The new directives.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
for directive in directives:
|
if replace:
|
||||||
changed = False
|
for directive in directives:
|
||||||
if len(directive) == 0:
|
changed = False
|
||||||
continue
|
if len(directive) == 0:
|
||||||
for index, line in enumerate(block):
|
continue
|
||||||
if len(line) > 0 and line[0] == directive[0]:
|
for index, line in enumerate(block):
|
||||||
block[index] = directive
|
if len(line) > 0 and line[0] == directive[0]:
|
||||||
changed = True
|
block[index] = directive
|
||||||
if not changed:
|
changed = True
|
||||||
raise errors.LetsEncryptMisconfigurationError(
|
if not changed:
|
||||||
'LetsEncrypt expected directive for %s in the Nginx config '
|
raise errors.LetsEncryptMisconfigurationError(
|
||||||
'but did not find it.' % directive[0])
|
'LetsEncrypt expected directive for %s in the Nginx '
|
||||||
|
'config but did not find it.' % directive[0])
|
||||||
|
else:
|
||||||
|
block.extend(directives)
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ class NginxConfiguratorTest(util.NginxTest):
|
|||||||
self.assertEqual(results[name],
|
self.assertEqual(results[name],
|
||||||
self.config.choose_vhost(name).names)
|
self.config.choose_vhost(name).names)
|
||||||
for name in bad_results:
|
for name in bad_results:
|
||||||
self.assertEqual(None, self.config.choose_vhost(name))
|
self.assertEqual(set([name]), self.config.choose_vhost(name).names)
|
||||||
|
|
||||||
def test_more_info(self):
|
def test_more_info(self):
|
||||||
self.assertTrue('nginx.conf' in self.config.more_info())
|
self.assertTrue('nginx.conf' in self.config.more_info())
|
||||||
|
|||||||
@@ -75,12 +75,12 @@ class DvsniPerformTest(util.NginxTest):
|
|||||||
self.assertEqual([0], self.sni.indices)
|
self.assertEqual([0], self.sni.indices)
|
||||||
|
|
||||||
@mock.patch("letsencrypt.client.plugins.nginx.configurator."
|
@mock.patch("letsencrypt.client.plugins.nginx.configurator."
|
||||||
"NginxConfigurator.save")
|
"NginxConfigurator.choose_vhost")
|
||||||
def test_perform(self, mock_save):
|
def test_perform(self, mock_choose):
|
||||||
self.sni.add_chall(self.achalls[1])
|
self.sni.add_chall(self.achalls[1])
|
||||||
responses = self.sni.perform()
|
mock_choose.return_value = None
|
||||||
self.assertTrue(responses is None)
|
result = self.sni.perform()
|
||||||
self.assertEqual(mock_save.call_count, 1)
|
self.assertTrue(result is None)
|
||||||
|
|
||||||
def test_perform0(self):
|
def test_perform0(self):
|
||||||
responses = self.sni.perform()
|
responses = self.sni.perform()
|
||||||
@@ -108,30 +108,31 @@ class DvsniPerformTest(util.NginxTest):
|
|||||||
self.assertTrue(['include', self.sni.challenge_conf] in http[1])
|
self.assertTrue(['include', self.sni.challenge_conf] in http[1])
|
||||||
|
|
||||||
def test_perform2(self):
|
def test_perform2(self):
|
||||||
self.sni.add_chall(self.achalls[0])
|
for achall in self.achalls:
|
||||||
self.sni.add_chall(self.achalls[2])
|
self.sni.add_chall(achall)
|
||||||
|
|
||||||
mock_setup_cert = mock.MagicMock(side_effect=[
|
mock_setup_cert = mock.MagicMock(side_effect=[
|
||||||
challenges.DVSNIResponse(s="nginxS0"),
|
challenges.DVSNIResponse(s="nginxS0"),
|
||||||
challenges.DVSNIResponse(s="nginxS1")])
|
challenges.DVSNIResponse(s="nginxS1"),
|
||||||
|
challenges.DVSNIResponse(s="nginxS2")])
|
||||||
# pylint: disable=protected-access
|
# pylint: disable=protected-access
|
||||||
self.sni._setup_challenge_cert = mock_setup_cert
|
self.sni._setup_challenge_cert = mock_setup_cert
|
||||||
|
|
||||||
responses = self.sni.perform()
|
responses = self.sni.perform()
|
||||||
|
|
||||||
self.assertEqual(mock_setup_cert.call_count, 2)
|
self.assertEqual(mock_setup_cert.call_count, 3)
|
||||||
|
|
||||||
self.assertEqual(
|
for index, achall in enumerate(self.achalls):
|
||||||
mock_setup_cert.call_args_list[0], mock.call(self.achalls[0]))
|
self.assertEqual(
|
||||||
self.assertEqual(
|
mock_setup_cert.call_args_list[index], mock.call(achall))
|
||||||
mock_setup_cert.call_args_list[1], mock.call(self.achalls[2]))
|
|
||||||
|
|
||||||
http = self.sni.configurator.parser.parsed[
|
http = self.sni.configurator.parser.parsed[
|
||||||
self.sni.configurator.parser.loc["root"]][-1]
|
self.sni.configurator.parser.loc["root"]][-1]
|
||||||
self.assertTrue(['include', self.sni.challenge_conf] in http[1])
|
self.assertTrue(['include', self.sni.challenge_conf] in http[1])
|
||||||
|
self.assertTrue(['server_name', 'blah'] in http[1][-2][1])
|
||||||
|
|
||||||
self.assertEqual(len(responses), 2)
|
self.assertEqual(len(responses), 3)
|
||||||
for i in xrange(2):
|
for i in xrange(3):
|
||||||
self.assertEqual(responses[i].s, "nginxS%d" % i)
|
self.assertEqual(responses[i].s, "nginxS%d" % i)
|
||||||
|
|
||||||
def test_mod_config(self):
|
def test_mod_config(self):
|
||||||
|
|||||||
@@ -140,6 +140,16 @@ class NginxParserTest(util.NginxTest):
|
|||||||
['foo', 'bar'],
|
['foo', 'bar'],
|
||||||
['ssl_certificate', '/etc/ssl/cert2.pem']])
|
['ssl_certificate', '/etc/ssl/cert2.pem']])
|
||||||
|
|
||||||
|
def test_add_http_directives(self):
|
||||||
|
nparser = parser.NginxParser(self.config_path, self.ssl_options)
|
||||||
|
filep = nparser.abs_path('nginx.conf')
|
||||||
|
block = [['server'],
|
||||||
|
[['listen', '80'],
|
||||||
|
['server_name', 'localhost']]]
|
||||||
|
nparser.add_http_directives(filep, block)
|
||||||
|
self.assertEqual(nparser.parsed[filep][-1][0], ['http'])
|
||||||
|
self.assertEqual(nparser.parsed[filep][-1][1][-1], block)
|
||||||
|
|
||||||
def test_replace_server_directives(self):
|
def test_replace_server_directives(self):
|
||||||
nparser = parser.NginxParser(self.config_path, self.ssl_options)
|
nparser = parser.NginxParser(self.config_path, self.ssl_options)
|
||||||
target = set(['.example.com', 'example.*'])
|
target = set(['.example.com', 'example.*'])
|
||||||
|
|||||||
Reference in New Issue
Block a user