mirror of
https://github.com/certbot/certbot.git
synced 2026-08-04 20:23:12 +02:00
Merge remote-tracking branch 'upstream/master' into multios_apache
This commit is contained in:
+6
-1
@@ -64,7 +64,7 @@ or for full help, type:
|
||||
|
||||
``letsencrypt-auto`` is the recommended method of running the Let's Encrypt
|
||||
client beta releases on systems that don't have a packaged version. Debian,
|
||||
Arch linux and FreeBSD now have native packages, so on those
|
||||
Arch linux, FreeBSD, and OpenBSD now have native packages, so on those
|
||||
systems you can just install ``letsencrypt`` (and perhaps
|
||||
``letsencrypt-apache``). If you'd like to run the latest copy from Git, or
|
||||
run your own locally modified copy of the client, follow the instructions in
|
||||
@@ -351,6 +351,11 @@ Operating System Packages
|
||||
* Port: ``cd /usr/ports/security/py-letsencrypt && make install clean``
|
||||
* Package: ``pkg install py27-letsencrypt``
|
||||
|
||||
**OpenBSD**
|
||||
|
||||
* Port: ``cd /usr/ports/security/letsencrypt/client && make install clean``
|
||||
* Package: ``pkg_add letsencrypt``
|
||||
|
||||
**Arch Linux**
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
@@ -59,7 +59,7 @@ let empty = Util.empty_dos
|
||||
let indent = Util.indent
|
||||
|
||||
(* borrowed from shellvars.aug *)
|
||||
let char_arg_dir = /([^\\ '"{\t\r\n]|[^ '"{\t\r\n]+[^\\ '"\t\r\n])|\\\\"|\\\\'/
|
||||
let char_arg_dir = /([^\\ '"{\t\r\n]|[^ '"{\t\r\n]+[^\\ \t\r\n])|\\\\"|\\\\'/
|
||||
let char_arg_sec = /[^ '"\t\r\n>]|\\\\"|\\\\'/
|
||||
let char_arg_wl = /([^\\ '"},\t\r\n]|[^ '"},\t\r\n]+[^\\ '"},\t\r\n])/
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
"""Apache Configuration based off of Augeas Configurator."""
|
||||
# pylint: disable=too-many-lines
|
||||
import filecmp
|
||||
import itertools
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
@@ -26,6 +25,7 @@ from letsencrypt_apache import tls_sni_01
|
||||
from letsencrypt_apache import obj
|
||||
from letsencrypt_apache import parser
|
||||
|
||||
from collections import defaultdict
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -921,15 +921,33 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
||||
"redirection")
|
||||
self._create_redirect_vhost(ssl_vhost)
|
||||
else:
|
||||
# Check if redirection already exists
|
||||
self._verify_no_redirects(general_vh)
|
||||
# Check if LetsEncrypt redirection already exists
|
||||
self._verify_no_letsencrypt_redirect(general_vh)
|
||||
|
||||
|
||||
# Note: if code flow gets here it means we didn't find the exact
|
||||
# letsencrypt RewriteRule config for redirection. Finding
|
||||
# another RewriteRule is likely to be fine in most or all cases,
|
||||
# but redirect loops are possible in very obscure cases; see #1620
|
||||
# for reasoning.
|
||||
if self._is_rewrite_exists(general_vh):
|
||||
logger.warn("Added an HTTP->HTTPS rewrite in addition to "
|
||||
"other RewriteRules; you may wish to check for "
|
||||
"overall consistency.")
|
||||
|
||||
# Add directives to server
|
||||
# Note: These are not immediately searchable in sites-enabled
|
||||
# even with save() and load()
|
||||
self.parser.add_dir(general_vh.path, "RewriteEngine", "on")
|
||||
self.parser.add_dir(general_vh.path, "RewriteRule",
|
||||
if not self._is_rewrite_engine_on(general_vh):
|
||||
self.parser.add_dir(general_vh.path, "RewriteEngine", "on")
|
||||
|
||||
if self.get_version() >= (2, 3, 9):
|
||||
self.parser.add_dir(general_vh.path, "RewriteRule",
|
||||
constants.REWRITE_HTTPS_ARGS_WITH_END)
|
||||
else:
|
||||
self.parser.add_dir(general_vh.path, "RewriteRule",
|
||||
constants.REWRITE_HTTPS_ARGS)
|
||||
|
||||
self.save_notes += ("Redirecting host in %s to ssl vhost in %s\n" %
|
||||
(general_vh.filep, ssl_vhost.filep))
|
||||
self.save()
|
||||
@@ -937,40 +955,67 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
||||
logger.info("Redirecting vhost in %s to ssl vhost in %s",
|
||||
general_vh.filep, ssl_vhost.filep)
|
||||
|
||||
def _verify_no_redirects(self, vhost):
|
||||
"""Checks to see if existing redirect is in place.
|
||||
def _verify_no_letsencrypt_redirect(self, vhost):
|
||||
"""Checks to see if a redirect was already installed by letsencrypt.
|
||||
|
||||
Checks to see if virtualhost already contains a rewrite or redirect
|
||||
returns boolean, integer
|
||||
Checks to see if virtualhost already contains a rewrite rule that is
|
||||
identical to Letsencrypt's redirection rewrite rule.
|
||||
|
||||
:param vhost: vhost to check
|
||||
:type vhost: :class:`~letsencrypt_apache.obj.VirtualHost`
|
||||
|
||||
:raises errors.PluginEnhancementAlreadyPresent: When the exact
|
||||
letsencrypt redirection WriteRule exists in virtual host.
|
||||
|
||||
errors.PluginError: When there exists directives that may hint
|
||||
other redirection. (TODO: We should not throw a PluginError,
|
||||
but that's for an other PR.)
|
||||
"""
|
||||
rewrite_path = self.parser.find_dir(
|
||||
"RewriteRule", None, start=vhost.path)
|
||||
redirect_path = self.parser.find_dir("Redirect", None, start=vhost.path)
|
||||
"RewriteRule", None, start=vhost.path)
|
||||
|
||||
if redirect_path:
|
||||
# "Existing Redirect directive for virtualhost"
|
||||
raise errors.PluginError("Existing Redirect present on HTTP vhost.")
|
||||
if rewrite_path:
|
||||
# "No existing redirection for virtualhost"
|
||||
if len(rewrite_path) != len(constants.REWRITE_HTTPS_ARGS):
|
||||
raise errors.PluginError("Unknown Existing RewriteRule")
|
||||
for match, arg in itertools.izip(
|
||||
rewrite_path, constants.REWRITE_HTTPS_ARGS):
|
||||
if self.aug.get(match) != arg:
|
||||
raise errors.PluginError("Unknown Existing RewriteRule")
|
||||
# There can be other RewriteRule directive lines in vhost config.
|
||||
# rewrite_args_dict keys are directive ids and the corresponding value
|
||||
# for each is a list of arguments to that directive.
|
||||
rewrite_args_dict = defaultdict(list)
|
||||
pat = r'.*(directive\[\d+\]).*'
|
||||
for match in rewrite_path:
|
||||
m = re.match(pat, match)
|
||||
if m:
|
||||
dir_id = m.group(1)
|
||||
rewrite_args_dict[dir_id].append(match)
|
||||
|
||||
raise errors.PluginEnhancementAlreadyPresent(
|
||||
"Let's Encrypt has already enabled redirection")
|
||||
if rewrite_args_dict:
|
||||
redirect_args = [constants.REWRITE_HTTPS_ARGS,
|
||||
constants.REWRITE_HTTPS_ARGS_WITH_END]
|
||||
|
||||
for matches in rewrite_args_dict.values():
|
||||
if [self.aug.get(x) for x in matches] in redirect_args:
|
||||
raise errors.PluginEnhancementAlreadyPresent(
|
||||
"Let's Encrypt has already enabled redirection")
|
||||
|
||||
def _is_rewrite_exists(self, vhost):
|
||||
"""Checks if there exists a RewriteRule directive in vhost
|
||||
|
||||
:param vhost: vhost to check
|
||||
:type vhost: :class:`~letsencrypt_apache.obj.VirtualHost`
|
||||
|
||||
:returns: True if a RewriteRule directive exists.
|
||||
:rtype: bool
|
||||
|
||||
"""
|
||||
rewrite_path = self.parser.find_dir(
|
||||
"RewriteRule", None, start=vhost.path)
|
||||
return bool(rewrite_path)
|
||||
|
||||
def _is_rewrite_engine_on(self, vhost):
|
||||
"""Checks if a RewriteEngine directive is on
|
||||
|
||||
:param vhost: vhost to check
|
||||
:type vhost: :class:`~letsencrypt_apache.obj.VirtualHost`
|
||||
|
||||
"""
|
||||
rewrite_engine_path = self.parser.find_dir("RewriteEngine", "on",
|
||||
start=vhost.path)
|
||||
if rewrite_engine_path:
|
||||
return self.parser.get_arg(rewrite_engine_path[0])
|
||||
return False
|
||||
|
||||
def _create_redirect_vhost(self, ssl_vhost):
|
||||
"""Creates an http_vhost specifically to redirect for the ssl_vhost.
|
||||
@@ -1007,6 +1052,13 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
||||
if ssl_vhost.aliases:
|
||||
serveralias = "ServerAlias " + " ".join(ssl_vhost.aliases)
|
||||
|
||||
rewrite_rule_args = []
|
||||
if self.get_version() >= (2, 3, 9):
|
||||
rewrite_rule_args = constants.REWRITE_HTTPS_ARGS_WITH_END
|
||||
else:
|
||||
rewrite_rule_args = constants.REWRITE_HTTPS_ARGS
|
||||
|
||||
|
||||
return ("<VirtualHost %s>\n"
|
||||
"%s \n"
|
||||
"%s \n"
|
||||
@@ -1020,7 +1072,7 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
|
||||
"</VirtualHost>\n"
|
||||
% (" ".join(str(addr) for addr in self._get_proposed_addrs(ssl_vhost)),
|
||||
servername, serveralias,
|
||||
" ".join(constants.REWRITE_HTTPS_ARGS)))
|
||||
" ".join(rewrite_rule_args)))
|
||||
|
||||
def _write_out_redirect(self, ssl_vhost, text):
|
||||
# This is the default name
|
||||
|
||||
@@ -64,8 +64,12 @@ AUGEAS_LENS_DIR = pkg_resources.resource_filename(
|
||||
|
||||
REWRITE_HTTPS_ARGS = [
|
||||
"^", "https://%{SERVER_NAME}%{REQUEST_URI}", "[L,QSA,R=permanent]"]
|
||||
"""Apache rewrite rule arguments used for redirections to https vhost"""
|
||||
"""Apache version<2.3.9 rewrite rule arguments used for redirections to https vhost"""
|
||||
|
||||
REWRITE_HTTPS_ARGS_WITH_END = [
|
||||
"^", "https://%{SERVER_NAME}%{REQUEST_URI}", "[END,QSA,R=permanent]"]
|
||||
"""Apache version >= 2.3.9 rewrite rule arguments used for redirections to
|
||||
https vhost"""
|
||||
|
||||
HSTS_ARGS = ["always", "set", "Strict-Transport-Security",
|
||||
"\"max-age=31536000; includeSubDomains\""]
|
||||
|
||||
@@ -676,6 +676,19 @@ class TwoVhost80Test(util.ApacheTest):
|
||||
def test_supported_enhancements(self):
|
||||
self.assertTrue(isinstance(self.config.supported_enhancements(), list))
|
||||
|
||||
|
||||
@mock.patch("letsencrypt.le_util.exe_exists")
|
||||
def test_enhance_unknown_vhost(self, mock_exe):
|
||||
self.config.parser.modules.add("rewrite_module")
|
||||
mock_exe.return_value = True
|
||||
ssl_vh = obj.VirtualHost(
|
||||
"fp", "ap", set([obj.Addr(("*", "443")), obj.Addr(("satoshi.com",))]),
|
||||
True, False)
|
||||
self.config.vhosts.append(ssl_vh)
|
||||
self.assertRaises(
|
||||
errors.PluginError,
|
||||
self.config.enhance, "satoshi.com", "redirect")
|
||||
|
||||
def test_enhance_unknown_enhancement(self):
|
||||
self.assertRaises(
|
||||
errors.PluginError,
|
||||
@@ -764,6 +777,8 @@ class TwoVhost80Test(util.ApacheTest):
|
||||
def test_redirect_well_formed_http(self, mock_exe, _):
|
||||
self.config.parser.update_runtime_variables = mock.Mock()
|
||||
mock_exe.return_value = True
|
||||
self.config.get_version = mock.Mock(return_value=(2, 2))
|
||||
|
||||
# This will create an ssl vhost for letsencrypt.demo
|
||||
self.config.enhance("letsencrypt.demo", "redirect")
|
||||
|
||||
@@ -783,6 +798,55 @@ class TwoVhost80Test(util.ApacheTest):
|
||||
|
||||
self.assertTrue("rewrite_module" in self.config.parser.modules)
|
||||
|
||||
def test_rewrite_rule_exists(self):
|
||||
# Skip the enable mod
|
||||
self.config.parser.modules.add("rewrite_module")
|
||||
self.config.get_version = mock.Mock(return_value=(2, 3, 9))
|
||||
self.config.parser.add_dir(
|
||||
self.vh_truth[3].path, "RewriteRule", ["Unknown"])
|
||||
self.assertTrue(self.config._is_rewrite_exists(self.vh_truth[3])) # pylint: disable=protected-access
|
||||
|
||||
def test_rewrite_engine_exists(self):
|
||||
# Skip the enable mod
|
||||
self.config.parser.modules.add("rewrite_module")
|
||||
self.config.get_version = mock.Mock(return_value=(2, 3, 9))
|
||||
self.config.parser.add_dir(
|
||||
self.vh_truth[3].path, "RewriteEngine", "on")
|
||||
self.assertTrue(self.config._is_rewrite_engine_on(self.vh_truth[3])) # pylint: disable=protected-access
|
||||
|
||||
|
||||
@mock.patch("letsencrypt.le_util.run_script")
|
||||
@mock.patch("letsencrypt.le_util.exe_exists")
|
||||
def test_redirect_with_existing_rewrite(self, mock_exe, _):
|
||||
self.config.parser.update_runtime_variables = mock.Mock()
|
||||
mock_exe.return_value = True
|
||||
self.config.get_version = mock.Mock(return_value=(2, 2))
|
||||
|
||||
# Create a preexisting rewrite rule
|
||||
self.config.parser.add_dir(
|
||||
self.vh_truth[3].path, "RewriteRule", ["Unknown"])
|
||||
self.config.save()
|
||||
|
||||
# This will create an ssl vhost for letsencrypt.demo
|
||||
self.config.enhance("letsencrypt.demo", "redirect")
|
||||
|
||||
# These are not immediately available in find_dir even with save() and
|
||||
# load(). They must be found in sites-available
|
||||
rw_engine = self.config.parser.find_dir(
|
||||
"RewriteEngine", "on", self.vh_truth[3].path)
|
||||
rw_rule = self.config.parser.find_dir(
|
||||
"RewriteRule", None, self.vh_truth[3].path)
|
||||
|
||||
self.assertEqual(len(rw_engine), 1)
|
||||
# three args to rw_rule + 1 arg for the pre existing rewrite
|
||||
self.assertEqual(len(rw_rule), 4)
|
||||
|
||||
self.assertTrue(rw_engine[0].startswith(self.vh_truth[3].path))
|
||||
self.assertTrue(rw_rule[0].startswith(self.vh_truth[3].path))
|
||||
|
||||
self.assertTrue("rewrite_module" in self.config.parser.modules)
|
||||
|
||||
|
||||
def test_redirect_with_conflict(self):
|
||||
self.config.parser.modules.add("rewrite_module")
|
||||
ssl_vh = obj.VirtualHost(
|
||||
@@ -797,43 +861,16 @@ class TwoVhost80Test(util.ApacheTest):
|
||||
def test_redirect_twice(self):
|
||||
# Skip the enable mod
|
||||
self.config.parser.modules.add("rewrite_module")
|
||||
self.config.get_version = mock.Mock(return_value=(2, 3, 9))
|
||||
|
||||
self.config.enhance("encryption-example.demo", "redirect")
|
||||
self.assertRaises(
|
||||
errors.PluginEnhancementAlreadyPresent,
|
||||
self.config.enhance, "encryption-example.demo", "redirect")
|
||||
|
||||
def test_unknown_rewrite(self):
|
||||
# Skip the enable mod
|
||||
self.config.parser.modules.add("rewrite_module")
|
||||
self.config.parser.add_dir(
|
||||
self.vh_truth[3].path, "RewriteRule", ["Unknown"])
|
||||
self.config.save()
|
||||
self.assertRaises(
|
||||
errors.PluginError,
|
||||
self.config.enhance, "letsencrypt.demo", "redirect")
|
||||
|
||||
def test_unknown_rewrite2(self):
|
||||
# Skip the enable mod
|
||||
self.config.parser.modules.add("rewrite_module")
|
||||
self.config.parser.add_dir(
|
||||
self.vh_truth[3].path, "RewriteRule", ["Unknown", "2", "3"])
|
||||
self.config.save()
|
||||
self.assertRaises(
|
||||
errors.PluginError,
|
||||
self.config.enhance, "letsencrypt.demo", "redirect")
|
||||
|
||||
def test_unknown_redirect(self):
|
||||
# Skip the enable mod
|
||||
self.config.parser.modules.add("rewrite_module")
|
||||
self.config.parser.add_dir(
|
||||
self.vh_truth[3].path, "Redirect", ["Unknown"])
|
||||
self.config.save()
|
||||
self.assertRaises(
|
||||
errors.PluginError,
|
||||
self.config.enhance, "letsencrypt.demo", "redirect")
|
||||
|
||||
def test_create_own_redirect(self):
|
||||
self.config.parser.modules.add("rewrite_module")
|
||||
self.config.get_version = mock.Mock(return_value=(2, 3, 9))
|
||||
# For full testing... give names...
|
||||
self.vh_truth[1].name = "default.com"
|
||||
self.vh_truth[1].aliases = set(["yes.default.com"])
|
||||
@@ -841,6 +878,17 @@ class TwoVhost80Test(util.ApacheTest):
|
||||
self.config._enable_redirect(self.vh_truth[1], "") # pylint: disable=protected-access
|
||||
self.assertEqual(len(self.config.vhosts), 7)
|
||||
|
||||
def test_create_own_redirect_for_old_apache_version(self):
|
||||
self.config.parser.modules.add("rewrite_module")
|
||||
self.config.get_version = mock.Mock(return_value=(2, 2))
|
||||
# For full testing... give names...
|
||||
self.vh_truth[1].name = "default.com"
|
||||
self.vh_truth[1].aliases = set(["yes.default.com"])
|
||||
|
||||
self.config._enable_redirect(self.vh_truth[1], "") # pylint: disable=protected-access
|
||||
self.assertEqual(len(self.config.vhosts), 7)
|
||||
|
||||
|
||||
def get_achalls(self):
|
||||
"""Return testing achallenges."""
|
||||
account_key = self.rsa512jwk
|
||||
|
||||
@@ -97,6 +97,7 @@ DeterminePythonVersion() {
|
||||
export LE_PYTHON=${LE_PYTHON:-python}
|
||||
else
|
||||
echo "Cannot find any Pythons... please install one!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
PYVER=`$LE_PYTHON --version 2>&1 | cut -d" " -f 2 | cut -d. -f1,2 | sed 's/\.//'`
|
||||
|
||||
@@ -407,9 +407,10 @@ class Client(object):
|
||||
logger.warning("No config is specified.")
|
||||
raise errors.Error("No config available")
|
||||
|
||||
redirect = config.redirect
|
||||
hsts = config.hsts
|
||||
uir = config.uir # Upgrade Insecure Requests
|
||||
supported = self.installer.supported_enhancements()
|
||||
redirect = config.redirect if "redirect" in supported else False
|
||||
hsts = config.hsts if "ensure-http-header" in supported else False
|
||||
uir = config.uir if "ensure-http-header" in supported else False
|
||||
|
||||
if redirect is None:
|
||||
redirect = enhancements.ask("redirect")
|
||||
|
||||
@@ -181,7 +181,9 @@ def main(cli_args=sys.argv[1:]):
|
||||
# RenewableCert object for this cert at all, which could
|
||||
# dramatically improve performance for large deployments
|
||||
# where autorenewal is widely turned off.
|
||||
cert = storage.RenewableCert(renewal_file, cli_config)
|
||||
cert = storage.RenewableCert(
|
||||
os.path.join(cli_config.renewal_configs_dir, renewal_file),
|
||||
cli_config)
|
||||
except errors.CertStorageError:
|
||||
# This indicates an invalid renewal configuration file, such
|
||||
# as one missing a required parameter (in the future, perhaps
|
||||
|
||||
@@ -260,7 +260,7 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes
|
||||
|
||||
:returns: The path to the current version of the specified
|
||||
member.
|
||||
:rtype: str
|
||||
:rtype: str or None
|
||||
|
||||
"""
|
||||
if kind not in ALL_FOUR:
|
||||
|
||||
@@ -240,6 +240,7 @@ class ClientTest(unittest.TestCase):
|
||||
mock_enhancements.ask.return_value = True
|
||||
installer = mock.MagicMock()
|
||||
self.client.installer = installer
|
||||
installer.supported_enhancements.return_value = ["redirect"]
|
||||
|
||||
self.client.enhance_config(["foo.bar"], config)
|
||||
installer.enhance.assert_called_once_with("foo.bar", "redirect", None)
|
||||
@@ -255,6 +256,7 @@ class ClientTest(unittest.TestCase):
|
||||
mock_enhancements.ask.return_value = True
|
||||
installer = mock.MagicMock()
|
||||
self.client.installer = installer
|
||||
installer.supported_enhancements.return_value = ["redirect", "ensure-http-header"]
|
||||
|
||||
config = ConfigHelper(redirect=True, hsts=False, uir=False)
|
||||
self.client.enhance_config(["foo.bar"], config)
|
||||
@@ -273,6 +275,17 @@ class ClientTest(unittest.TestCase):
|
||||
self.assertEqual(installer.save.call_count, 3)
|
||||
self.assertEqual(installer.restart.call_count, 3)
|
||||
|
||||
@mock.patch("letsencrypt.client.enhancements")
|
||||
def test_enhance_config_unsupported(self, mock_enhancements):
|
||||
installer = mock.MagicMock()
|
||||
self.client.installer = installer
|
||||
installer.supported_enhancements.return_value = []
|
||||
|
||||
config = ConfigHelper(redirect=None, hsts=True, uir=True)
|
||||
self.client.enhance_config(["foo.bar"], config)
|
||||
installer.enhance.assert_not_called()
|
||||
mock_enhancements.ask.assert_not_called()
|
||||
|
||||
def test_enhance_config_no_installer(self):
|
||||
config = ConfigHelper(redirect=True, hsts=False, uir=False)
|
||||
self.assertRaises(errors.Error,
|
||||
@@ -285,6 +298,7 @@ class ClientTest(unittest.TestCase):
|
||||
mock_enhancements.ask.return_value = True
|
||||
installer = mock.MagicMock()
|
||||
self.client.installer = installer
|
||||
installer.supported_enhancements.return_value = ["redirect"]
|
||||
installer.enhance.side_effect = errors.PluginError
|
||||
|
||||
config = ConfigHelper(redirect=True, hsts=False, uir=False)
|
||||
@@ -301,6 +315,7 @@ class ClientTest(unittest.TestCase):
|
||||
mock_enhancements.ask.return_value = True
|
||||
installer = mock.MagicMock()
|
||||
self.client.installer = installer
|
||||
installer.supported_enhancements.return_value = ["redirect"]
|
||||
installer.save.side_effect = errors.PluginError
|
||||
|
||||
config = ConfigHelper(redirect=True, hsts=False, uir=False)
|
||||
@@ -317,6 +332,7 @@ class ClientTest(unittest.TestCase):
|
||||
mock_enhancements.ask.return_value = True
|
||||
installer = mock.MagicMock()
|
||||
self.client.installer = installer
|
||||
installer.supported_enhancements.return_value = ["redirect"]
|
||||
installer.restart.side_effect = [errors.PluginError, None]
|
||||
|
||||
config = ConfigHelper(redirect=True, hsts=False, uir=False)
|
||||
@@ -335,6 +351,7 @@ class ClientTest(unittest.TestCase):
|
||||
mock_enhancements.ask.return_value = True
|
||||
installer = mock.MagicMock()
|
||||
self.client.installer = installer
|
||||
installer.supported_enhancements.return_value = ["redirect"]
|
||||
installer.restart.side_effect = errors.PluginError
|
||||
installer.rollback_checkpoints.side_effect = errors.ReverterError
|
||||
|
||||
|
||||
@@ -764,6 +764,8 @@ class RenewableCertTests(BaseRenewableCertTest):
|
||||
|
||||
def test_bad_config_file(self):
|
||||
from letsencrypt import renewer
|
||||
os.unlink(os.path.join(self.cli_config.renewal_configs_dir,
|
||||
"example.org.conf"))
|
||||
with open(os.path.join(self.cli_config.renewal_configs_dir,
|
||||
"bad.conf"), "w") as f:
|
||||
f.write("incomplete = configfile\n")
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
<VirtualHost *:80>
|
||||
|
||||
WSGIDaemonProcess _graphite processes=5 threads=5 display-name='%{GROUP}' inactivity-timeout=120 user=_graphite group=_graphite
|
||||
WSGIProcessGroup _graphite
|
||||
WSGIImportScript /usr/share/graphite-web/graphite.wsgi process-group=_graphite application-group=%{GLOBAL}
|
||||
WSGIScriptAlias / /usr/share/graphite-web/graphite.wsgi
|
||||
|
||||
Alias /content/ /usr/share/graphite-web/static/
|
||||
<Location "/content/">
|
||||
SetHandler None
|
||||
</Location>
|
||||
|
||||
ErrorLog ${APACHE_LOG_DIR}/graphite-web_error.log
|
||||
|
||||
# Possible values include: debug, info, notice, warn, error, crit,
|
||||
# alert, emerg.
|
||||
LogLevel warn
|
||||
|
||||
CustomLog ${APACHE_LOG_DIR}/graphite-web_access.log combined
|
||||
|
||||
</VirtualHost>
|
||||
@@ -0,0 +1,120 @@
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/pem.h>
|
||||
|
||||
// This program can be used to perform RSA public key signatures given only
|
||||
// the hash of the file to be signed as input.
|
||||
|
||||
// Sign with SHA1
|
||||
#define HASH_SIZE 20
|
||||
|
||||
void usage() {
|
||||
printf("half-sign <private key file> [binary hash file]\n");
|
||||
printf("\n");
|
||||
printf(" Computes and prints a binary RSA signature over data given the SHA1 hash of\n");
|
||||
printf(" the data as input.\n");
|
||||
printf("\n");
|
||||
printf(" <private key file> should be PEM encoded.\n");
|
||||
printf("\n");
|
||||
printf(" The input SHA1 hash should be %d bytes in length. If no binary hash file is\n", HASH_SIZE);
|
||||
printf(" specified, it will be read from stdin.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void sign_hashed_data(EVP_PKEY *signing_key, unsigned char *md, size_t mdlen) {
|
||||
// cribbed from the openssl EVP_PKEY_sign man page
|
||||
EVP_PKEY_CTX *ctx;
|
||||
unsigned char *sig;
|
||||
size_t siglen;
|
||||
|
||||
/* NB: assumes signing_key, md and mdlen are already set up
|
||||
* and that signing_key is an RSA private key
|
||||
*/
|
||||
ctx = EVP_PKEY_CTX_new(signing_key, NULL);
|
||||
if ((!ctx)
|
||||
|| (EVP_PKEY_sign_init(ctx) <= 0)
|
||||
|| (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0)
|
||||
|| (EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha1()) <= 0)) {
|
||||
fprintf(stderr, "Failure establishing ctx for signature\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Determine buffer length */
|
||||
if (EVP_PKEY_sign(ctx, NULL, &siglen, md, mdlen) <= 0) {
|
||||
fprintf(stderr, "Unable to determine buffer length for signature\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
sig = OPENSSL_malloc(siglen);
|
||||
|
||||
if (!sig) {
|
||||
fprintf(stderr, "Malloc failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (EVP_PKEY_sign(ctx, sig, &siglen, md, mdlen) <= 0) {
|
||||
fprintf(stderr, "Signature error\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Signature is siglen bytes written to buffer sig */
|
||||
fwrite(sig, siglen, 1, stdout);
|
||||
}
|
||||
|
||||
EVP_PKEY *read_private_key(char *filename) {
|
||||
FILE *keyfile;
|
||||
EVP_PKEY *privkey;
|
||||
keyfile = fopen(filename, "r");
|
||||
if (!keyfile) {
|
||||
fprintf(stderr, "Failed to open private key.pem file %s\n", filename);
|
||||
exit(1);
|
||||
}
|
||||
privkey = PEM_read_PrivateKey(keyfile, NULL, NULL, NULL);
|
||||
if (!privkey) {
|
||||
fprintf(stderr, "Failed to read PEM private key from %s\n", filename);
|
||||
exit(1);
|
||||
}
|
||||
if (EVP_PKEY_type(privkey->type) != EVP_PKEY_RSA) {
|
||||
fprintf(stderr, "%s was a non-RSA key\n", filename);
|
||||
exit(1);
|
||||
}
|
||||
return privkey;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
FILE *input;
|
||||
unsigned char *buffer;
|
||||
int test;
|
||||
EVP_PKEY *privkey;
|
||||
if (argc > 3 || argc < 2)
|
||||
usage();
|
||||
if (argc < 3 || strcmp(argv[2],"-") == 0)
|
||||
input = stdin;
|
||||
else {
|
||||
input = fopen(argv[2], "r");
|
||||
if (!input) usage();
|
||||
}
|
||||
privkey = read_private_key(argv[1]);
|
||||
buffer = malloc(HASH_SIZE);
|
||||
if (!buffer) {
|
||||
fprintf(stderr, "Argh, malloc failed\n");
|
||||
exit(1);
|
||||
}
|
||||
if (fread(buffer, HASH_SIZE, 1, input) != 1) {
|
||||
perror("half-sign: Failed to read SHA1 from input\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
test = fgetc(input);
|
||||
if (test != EOF && test != '\n') {
|
||||
fprintf(stderr,"Error, more than %d bytes fed to half-sign\n", HASH_SIZE);
|
||||
fprintf(stderr,"Last byte was :%d\n" , (int) test);
|
||||
exit(1);
|
||||
}
|
||||
sign_hashed_data(privkey, buffer, HASH_SIZE);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,13 +1,43 @@
|
||||
#!/bin/sh -xe
|
||||
#!/bin/bash -xe
|
||||
# Release dev packages to PyPI
|
||||
|
||||
Usage() {
|
||||
echo Usage:
|
||||
echo "$0 [ --production ]"
|
||||
exit 1
|
||||
}
|
||||
|
||||
if [ "`dirname $0`" != "tools" ] ; then
|
||||
echo Please run this script from the repo root
|
||||
exit 1
|
||||
fi
|
||||
|
||||
CheckVersion() {
|
||||
# Args: <description of version type> <version number>
|
||||
if ! echo "$2" | grep -q -e '[0-9]\+.[0-9]\+.[0-9]\+' ; then
|
||||
echo "$1 doesn't look like 1.2.3"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
if [ "$1" = "--production" ] ; then
|
||||
version="$2"
|
||||
CheckVersion Version "$version"
|
||||
echo Releasing production version "$version"...
|
||||
nextversion="$3"
|
||||
CheckVersion "Next version" "$nextversion"
|
||||
RELEASE_BRANCH="candidate-$version"
|
||||
else
|
||||
version=`grep "__version__" letsencrypt/__init__.py | cut -d\' -f2 | sed s/\.dev0//`
|
||||
version="$version.dev$(date +%Y%m%d)1"
|
||||
RELEASE_BRANCH="dev-release"
|
||||
echo Releasing developer version "$version"...
|
||||
fi
|
||||
|
||||
RELEASE_GPG_KEY=${RELEASE_GPG_KEY:-A2CFB51FA275A7286234E7B24D17C995CD9775F2}
|
||||
# Needed to fix problems with git signatures and pinentry
|
||||
export GPG_TTY=$(tty)
|
||||
|
||||
version="0.0.0.dev$(date +%Y%m%d)"
|
||||
DEV_RELEASE_BRANCH="dev-release"
|
||||
RELEASE_GPG_KEY=A2CFB51FA275A7286234E7B24D17C995CD9775F2
|
||||
|
||||
# port for a local Python Package Index (used in testing)
|
||||
PORT=${PORT:-1234}
|
||||
|
||||
@@ -36,21 +66,29 @@ pip install -U wheel # setup.py bdist_wheel
|
||||
# from current env when creating a child env
|
||||
pip install -U virtualenv
|
||||
|
||||
root="$(mktemp -d -t le.$version.XXX)"
|
||||
root_without_le="$version.$$"
|
||||
root="./releases/le.$root_without_le"
|
||||
|
||||
echo "Cloning into fresh copy at $root" # clean repo = no artificats
|
||||
git clone . $root
|
||||
git rev-parse HEAD
|
||||
cd $root
|
||||
git branch -f "$DEV_RELEASE_BRANCH"
|
||||
git checkout "$DEV_RELEASE_BRANCH"
|
||||
if [ "$RELEASE_BRANCH" != "candidate-$version" ] ; then
|
||||
git branch -f "$RELEASE_BRANCH"
|
||||
fi
|
||||
git checkout "$RELEASE_BRANCH"
|
||||
|
||||
for pkg_dir in $SUBPKGS
|
||||
do
|
||||
sed -i $x "s/^version.*/version = '$version'/" $pkg_dir/setup.py
|
||||
done
|
||||
sed -i "s/^__version.*/__version__ = '$version'/" letsencrypt/__init__.py
|
||||
SetVersion() {
|
||||
ver="$1"
|
||||
for pkg_dir in $SUBPKGS
|
||||
do
|
||||
sed -i "s/^version.*/version = '$ver'/" $pkg_dir/setup.py
|
||||
done
|
||||
sed -i "s/^__version.*/__version__ = '$ver'/" letsencrypt/__init__.py
|
||||
|
||||
git add -p # interactive user input
|
||||
git add -p $SUBPKGS # interactive user input
|
||||
}
|
||||
SetVersion "$version"
|
||||
git commit --gpg-sign="$RELEASE_GPG_KEY" -m "Release $version"
|
||||
git tag --local-user "$RELEASE_GPG_KEY" \
|
||||
--sign --message "Release $version" "$tag"
|
||||
@@ -68,7 +106,7 @@ do
|
||||
echo "Signing ($pkg_dir)"
|
||||
for x in dist/*.tar.gz dist/*.whl
|
||||
do
|
||||
gpg2 --detach-sign --armor --sign $x
|
||||
gpg -u "$RELEASE_GPG_KEY" --detach-sign --armor --sign $x
|
||||
done
|
||||
|
||||
cd -
|
||||
@@ -97,16 +135,44 @@ pip install \
|
||||
letsencrypt $SUBPKGS
|
||||
# stop local PyPI
|
||||
kill $!
|
||||
cd ~-
|
||||
|
||||
# freeze before installing anything else, so that we know end-user KGS
|
||||
# make sure "twine upload" doesn't catch "kgs"
|
||||
if [ -d ../kgs ] ; then
|
||||
echo Deleting old kgs...
|
||||
rm -rf ../kgs
|
||||
fi
|
||||
mkdir ../kgs
|
||||
kgs="../kgs/$version"
|
||||
pip freeze | tee $kgs
|
||||
pip install nose
|
||||
nosetests letsencrypt $subpkgs_modules
|
||||
for module in letsencrypt $subpkgs_modules ; do
|
||||
echo testing $module
|
||||
nosetests $module
|
||||
done
|
||||
deactivate
|
||||
|
||||
cd ..
|
||||
echo Now in $PWD
|
||||
name=${root_without_le%.*}
|
||||
ext="${root_without_le##*.}"
|
||||
rev="$(git rev-parse --short HEAD)"
|
||||
echo tar cJvf $name.$rev.tar.xz $name.$rev
|
||||
echo gpg -U $RELEASE_GPG_KEY --detach-sign --armor $name.$rev.tar.xz
|
||||
cd ~-
|
||||
|
||||
echo "New root: $root"
|
||||
echo "KGS is at $root/kgs"
|
||||
echo "Test commands (in the letstest repo):"
|
||||
echo 'python multitester.py targets.yaml $AWS_KEY $USERNAME scripts/test_leauto_upgrades.sh --alt_pip $YOUR_PIP_REPO --branch public-beta'
|
||||
echo 'python multitester.py targets.yaml $AWK_KEY $USERNAME scripts/test_letsencrypt_auto_certonly_standalone.sh --branch candidate-0.1.1'
|
||||
echo 'python multitester.py --saveinstances targets.yaml $AWS_KEY $USERNAME scripts/test_apache2.sh'
|
||||
echo "In order to upload packages run the following command:"
|
||||
echo twine upload "$root/dist.$version/*/*"
|
||||
|
||||
if [ "$RELEASE_BRANCH" = candidate-"$version" ] ; then
|
||||
SetVersion "$nextversion".dev0
|
||||
git diff
|
||||
git commit -m "Bump version to $nextversion"
|
||||
fi
|
||||
+1
-1
@@ -16,7 +16,7 @@ fi
|
||||
|
||||
cover () {
|
||||
if [ "$1" = "letsencrypt" ]; then
|
||||
min=97
|
||||
min=98
|
||||
elif [ "$1" = "acme" ]; then
|
||||
min=100
|
||||
elif [ "$1" = "letsencrypt_apache" ]; then
|
||||
|
||||
Reference in New Issue
Block a user