Refactor --csr handling to run early enough for --webroot

This commit is contained in:
Peter Eckersley
2016-02-08 18:06:46 -08:00
parent c8623fdd91
commit c23aa37f4b
3 changed files with 36 additions and 37 deletions
+23 -1
View File
@@ -684,7 +684,7 @@ def obtain_cert(config, plugins, lineage=None):
# This is a special case; cert and chain are simply saved
if config.csr is not None:
assert lineage is None, "Did not expect a CSR with a RenewableCert"
certr, chain = le_client.obtain_certificate_from_csr(_process_domain)
certr, chain = le_client.obtain_certificate_from_csr(config.domains, config.actual_csr)
if config.dry_run:
logger.info(
"Dry run: skipping saving certificate to %s", config.cert_path)
@@ -1106,8 +1106,30 @@ class HelpfulArgumentParser(object):
"'certonly' or 'renew' subcommands")
parsed_args.break_my_certs = parsed_args.staging = True
if parsed_args.csr:
self.handle_csr(parsed_args)
return parsed_args
def handle_csr(self, parsed_args):
"""
Process a --csr flag. This needs to happen early enought that the
webroot plugin can know about the calls to _process_domain
"""
csr = le_util.CSR(file=parsed_args.csr[0], data=parsed_args.csr[1], form="der")
# TODO: add CN to domains?
domains = crypto_util.get_sans_from_csr(csr.data, OpenSSL.crypto.FILETYPE_ASN1)
for d in domains:
_process_domain(parsed_args, d)
parsed_args.actual_csr = csr
csr_domains, config_domains = set(domains), set(parsed_args.domains)
if csr_domains != config_domains:
raise errors.ConfigurationError(
"Inconsistent domain requests:\ncsr: {0}\ncli config: {1}"
.format(", ".join(csr_domains), ", ".join(config_domains))
)
def determine_verb(self):
"""Determines the verb/subcommand provided by the user.
+2 -30
View File
@@ -195,7 +195,7 @@ class Client(object):
else:
self.auth_handler = None
def _obtain_certificate(self, domains, csr):
def obtain_certificate_from_csr(self, domains, csr):
"""Obtain certificate.
Internal function with precondition that `domains` are
@@ -228,34 +228,6 @@ class Client(object):
authzr)
return certr, self.acme.fetch_chain(certr)
def obtain_certificate_from_csr(self, domain_callback):
"""Obtain certficiate from CSR.
:param function(config, domains) domain_callback: callback for each
domain extracted from the CSR, to ensure that webroot-map and similar
housekeeping in cli.py is performed correctly
:returns: `.CertificateResource` and certificate chain (as
returned by `.fetch_chain`).
:rtype: tuple
"""
#raise TypeError("About to call %r" % le_util.CSR)
csr = le_util.CSR(file=self.config.csr[0], data=self.config.csr[1], form="der")
# TODO: add CN to domains?
domains = crypto_util.get_sans_from_csr(csr.data, OpenSSL.crypto.FILETYPE_ASN1)
for d in domains:
domain_callback(self.config, d)
csr_domains, config_domains = set(domains), set(self.config.domains)
if csr_domains != config_domains:
raise errors.ConfigurationError(
"Inconsistent domain requests:\ncsr: {0}\ncli config: {1}"
.format(", ".join(csr_domains), ", ".join(config_domains))
)
return self._obtain_certificate(domains, csr)
def obtain_certificate(self, domains):
"""Obtains a certificate from the ACME server.
@@ -276,7 +248,7 @@ class Client(object):
self.config.rsa_key_size, self.config.key_dir)
csr = crypto_util.init_save_csr(key, domains, self.config.csr_dir)
return self._obtain_certificate(domains, csr) + (key, csr)
return self.obtain_certificate_from_csr(domains, csr) + (key, csr)
def obtain_and_enroll_certificate(self, domains):
"""Obtain and enroll certificate.
+11 -6
View File
@@ -109,21 +109,26 @@ class ClientTest(unittest.TestCase):
self.client.auth_handler.get_authorizations())
self.acme.fetch_chain.assert_called_once_with(mock.sentinel.certr)
def test_obtain_certificate_from_csr(self):
# FIXME move parts of this to test_cli.py...
@mock.patch("letsencrypt.cli._process_domain")
def test_obtain_certificate_from_csr(self, mock_process_domain):
self._mock_obtain_certificate()
mock_process_domain = mock.MagicMock()
from letsencrypt import cli
test_csr = le_util.CSR(form="der", file=None, data=CSR_SAN)
mock_parsed_args = mock.MagicMock()
with mock.patch("letsencrypt.client.le_util.CSR") as mock_CSR:
mock_CSR.return_value = test_csr
self.client.config.domains = self.eg_domains
self.assertEqual(
(mock.sentinel.certr, mock.sentinel.chain),
self.client.obtain_certificate_from_csr(mock_process_domain))
mock_parsed_args.domains = self.eg_domains
mock_parser = mock.MagicMock(cli.HelpfulArgumentParser)
cli.HelpfulArgumentParser.handle_csr(mock_parser, mock_parsed_args)
# make sure cli processing occurred
cli_processed = (call[0][1] for call in mock_process_domain.call_args_list)
self.assertEqual(set(cli_processed), set(("example.com", "www.example.com")))
self.assertEqual(
(mock.sentinel.certr, mock.sentinel.chain),
self.client.obtain_certificate_from_csr(self.eg_domains, test_csr))
# and that the cert was obtained correctly
self._check_obtain_certificate()