From 62ea74b9e4a66afedcf4625667e082497b719eea Mon Sep 17 00:00:00 2001 From: Ingolf Becker Date: Tue, 8 Dec 2015 13:22:52 +0000 Subject: [PATCH] Modify apache plugin to work on setups where apache listens to a specific ip --- .../letsencrypt_apache/configurator.py | 50 +++++++++++++------ .../tests/configurator_test.py | 33 ++++++++++++ 2 files changed, 69 insertions(+), 14 deletions(-) diff --git a/letsencrypt-apache/letsencrypt_apache/configurator.py b/letsencrypt-apache/letsencrypt_apache/configurator.py index 98b0b8820..76045bee1 100644 --- a/letsencrypt-apache/letsencrypt_apache/configurator.py +++ b/letsencrypt-apache/letsencrypt_apache/configurator.py @@ -545,21 +545,43 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator): # Check for Listen # Note: This could be made to also look for ip:443 combo - if not self.parser.find_dir("Listen", port): - logger.debug("No Listen %s directive found. Setting the " - "Apache Server to Listen on port %s", port, port) - - if port == "443": - args = [port] + listens = [self.parser.get_arg(x).split()[0] for x in self.parser.find_dir("Listen")] + # In case no Listens are set (which really is a broken apache config) + if not listens: + listens = ["80"] + for listen in listens: + # For any listen statement, check if the machine also listens on Port 443. + # If not, add such a listen statement. + if len(listen.split(":")) == 1: + # Its listening to all interfaces + if port not in listens: + if port == "443": + args = [port] + else: + # Non-standard ports should specify https protocol + args = [port, "https"] + self.parser.add_dir_to_ifmodssl( + parser.get_aug_path( + self.parser.loc["listen"]), "Listen", args) + self.save_notes += "Added Listen %s directive to %s\n" % ( + port, self.parser.loc["listen"]) + listens.append(port) else: - # Non-standard ports should specify https protocol - args = [port, "https"] - - self.parser.add_dir_to_ifmodssl( - parser.get_aug_path( - self.parser.loc["listen"]), "Listen", args) - self.save_notes += "Added Listen %s directive to %s\n" % ( - port, self.parser.loc["listen"]) + # The Listen statement specifies an ip + _, ip = listen[::-1].split(":", 1) + ip = ip[::-1] + if "%s:%s" %(ip, port) not in listens: + if port == "443": + args = ["%s:%s" %(ip, port)] + else: + # Non-standard ports should specify https protocol + args = ["%s:%s" %(ip, port), "https"] + self.parser.add_dir_to_ifmodssl( + parser.get_aug_path( + self.parser.loc["listen"]), "Listen", args) + self.save_notes += "Added Listen %s:%s directive to %s\n" % ( + ip, port, self.parser.loc["listen"]) + listens.append("%s:%s" %(ip, port)) def make_addrs_sni_ready(self, addrs): """Checks to see if the server is ready for SNI challenges. diff --git a/letsencrypt-apache/letsencrypt_apache/tests/configurator_test.py b/letsencrypt-apache/letsencrypt_apache/tests/configurator_test.py index fcccfaae2..991704144 100644 --- a/letsencrypt-apache/letsencrypt_apache/tests/configurator_test.py +++ b/letsencrypt-apache/letsencrypt_apache/tests/configurator_test.py @@ -391,6 +391,39 @@ class TwoVhost80Test(util.ApacheTest): self.assertEqual(mock_add_dir.call_count, 2) + def test_prepare_server_https_named_listen(self): + mock_find = mock.Mock() + mock_find.return_value = ["test1", "test2", "test3"] + mock_get = mock.Mock() + mock_get.side_effect = ["1.2.3.4:80", "[::1]:80", "1.1.1.1:443"] + mock_add_dir = mock.Mock() + mock_enable = mock.Mock() + + self.config.parser.find_dir = mock_find + self.config.parser.get_arg = mock_get + self.config.parser.add_dir_to_ifmodssl = mock_add_dir + self.config.enable_mod = mock_enable + + # Test Listen statements with specific ip listeed + self.config.prepare_server_https("443") + # Should only be 2 here, as the third interface already listens to the correct port + self.assertEqual(mock_add_dir.call_count, 2) + + # Check argument to new Listen statements + self.assertEqual(mock_add_dir.call_args_list[0][0][2], ["1.2.3.4:443"]) + self.assertEqual(mock_add_dir.call_args_list[1][0][2], ["[::1]:443"]) + + # Reset return lists and inputs + mock_add_dir.reset_mock() + mock_get.side_effect = ["1.2.3.4:80", "[::1]:80", "1.1.1.1:443"] + + # Test + self.config.prepare_server_https("8080", temp=True) + self.assertEqual(mock_add_dir.call_count, 3) + self.assertEqual(mock_add_dir.call_args_list[0][0][2], ["1.2.3.4:8080", "https"]) + self.assertEqual(mock_add_dir.call_args_list[1][0][2], ["[::1]:8080", "https"]) + self.assertEqual(mock_add_dir.call_args_list[2][0][2], ["1.1.1.1:8080", "https"]) + def test_make_vhost_ssl(self): ssl_vhost = self.config.make_vhost_ssl(self.vh_truth[0])