Hello community, here is the log from the commit of package python-acme for openSUSE:Factory checked in at 2020-07-15 15:01:22 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-acme (Old) and /work/SRC/openSUSE:Factory/.python-acme.new.3060 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-acme" Wed Jul 15 15:01:22 2020 rev:45 rq:820645 version:1.6.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-acme/python-acme.changes 2020-06-11 15:15:27.678955627 +0200 +++ /work/SRC/openSUSE:Factory/.python-acme.new.3060/python-acme.changes 2020-07-15 15:01:41.151214944 +0200 @@ -1,0 +2,9 @@ +Mon Jul 13 08:27:35 UTC 2020 - Marketa Calabkova <[email protected]> + +- update to version 1.6.0 + * Support for alternative certificate chains in the acme module. + * Added --preferred-chain <issuer CN>. If a CA offers multiple + certificate chains, it may be used to indicate to Certbot which + chain should be preferred. + +------------------------------------------------------------------- Old: ---- acme-1.5.0.tar.gz acme-1.5.0.tar.gz.asc New: ---- acme-1.6.0.tar.gz acme-1.6.0.tar.gz.asc ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-acme.spec ++++++ --- /var/tmp/diff_new_pack.wHBi9c/_old 2020-07-15 15:01:42.887216638 +0200 +++ /var/tmp/diff_new_pack.wHBi9c/_new 2020-07-15 15:01:42.891216641 +0200 @@ -19,7 +19,7 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} %define libname acme Name: python-%{libname} -Version: 1.5.0 +Version: 1.6.0 Release: 0 Summary: Python library for the ACME protocol License: Apache-2.0 @@ -30,7 +30,7 @@ BuildRequires: %{python_module cryptography >= 1.2.3} BuildRequires: %{python_module josepy >= 1.1.0} BuildRequires: %{python_module mock} -BuildRequires: %{python_module pyOpenSSL >= 0.13.1} +BuildRequires: %{python_module pyOpenSSL >= 0.15.1} BuildRequires: %{python_module pyRFC3339} BuildRequires: %{python_module pytest} BuildRequires: %{python_module pytz} @@ -43,7 +43,7 @@ BuildRequires: python-rpm-macros Requires: python-cryptography >= 1.2.3 Requires: python-josepy >= 1.1.0 -Requires: python-pyOpenSSL >= 0.13.1 +Requires: python-pyOpenSSL >= 0.15.1 Requires: python-pyRFC3339 Requires: python-pytz Requires: python-requests >= 2.6.0 ++++++ acme-1.5.0.tar.gz -> acme-1.6.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/acme-1.5.0/PKG-INFO new/acme-1.6.0/PKG-INFO --- old/acme-1.5.0/PKG-INFO 2020-06-02 19:12:54.000000000 +0200 +++ new/acme-1.6.0/PKG-INFO 2020-07-07 19:13:32.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: acme -Version: 1.5.0 +Version: 1.6.0 Summary: ACME protocol implementation in Python Home-page: https://github.com/letsencrypt/letsencrypt Author: Certbot Project diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/acme-1.5.0/acme/client.py new/acme-1.6.0/acme/client.py --- old/acme-1.5.0/acme/client.py 2020-06-02 19:12:31.000000000 +0200 +++ new/acme-1.6.0/acme/client.py 2020-07-07 19:13:19.000000000 +0200 @@ -13,6 +13,7 @@ import OpenSSL import requests from requests.adapters import HTTPAdapter +from requests.utils import parse_header_links from requests_toolbelt.adapters.source import SourceAddressAdapter import six from six.moves import http_client @@ -733,11 +734,13 @@ raise errors.ValidationError(failed) return orderr.update(authorizations=responses) - def finalize_order(self, orderr, deadline): + def finalize_order(self, orderr, deadline, fetch_alternative_chains=False): """Finalize an order and obtain a certificate. :param messages.OrderResource orderr: order to finalize :param datetime.datetime deadline: when to stop polling and timeout + :param bool fetch_alternative_chains: whether to also fetch alternative + certificate chains :returns: finalized order :rtype: messages.OrderResource @@ -754,8 +757,13 @@ if body.error is not None: raise errors.IssuanceError(body.error) if body.certificate is not None: - certificate_response = self._post_as_get(body.certificate).text - return orderr.update(body=body, fullchain_pem=certificate_response) + certificate_response = self._post_as_get(body.certificate) + orderr = orderr.update(body=body, fullchain_pem=certificate_response.text) + if fetch_alternative_chains: + alt_chains_urls = self._get_links(certificate_response, 'alternate') + alt_chains = [self._post_as_get(url).text for url in alt_chains_urls] + orderr = orderr.update(alternative_fullchains_pem=alt_chains) + return orderr raise errors.TimeoutError() def revoke(self, cert, rsn): @@ -785,6 +793,20 @@ new_args = args[:1] + (None,) + args[1:] return self._post(*new_args, **kwargs) + def _get_links(self, response, relation_type): + """ + Retrieves all Link URIs of relation_type from the response. + :param requests.Response response: The requests HTTP response. + :param str relation_type: The relation type to filter by. + """ + # Can't use response.links directly because it drops multiple links + # of the same relation type, which is possible in RFC8555 responses. + if not 'Link' in response.headers: + return [] + links = parse_header_links(response.headers['Link']) + return [l['url'] for l in links + if 'rel' in l and 'url' in l and l['rel'] == relation_type] + class BackwardsCompatibleClientV2(object): """ACME client wrapper that tends towards V2-style calls, but @@ -863,11 +885,13 @@ return messages.OrderResource(authorizations=authorizations, csr_pem=csr_pem) return self.client.new_order(csr_pem) - def finalize_order(self, orderr, deadline): + def finalize_order(self, orderr, deadline, fetch_alternative_chains=False): """Finalize an order and obtain a certificate. :param messages.OrderResource orderr: order to finalize :param datetime.datetime deadline: when to stop polling and timeout + :param bool fetch_alternative_chains: whether to also fetch alternative + certificate chains :returns: finalized order :rtype: messages.OrderResource @@ -898,7 +922,7 @@ chain = crypto_util.dump_pyopenssl_chain(chain).decode() return orderr.update(fullchain_pem=(cert + chain)) - return self.client.finalize_order(orderr, deadline) + return self.client.finalize_order(orderr, deadline, fetch_alternative_chains) def revoke(self, cert, rsn): """Revoke certificate. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/acme-1.5.0/acme/messages.py new/acme-1.6.0/acme/messages.py --- old/acme-1.5.0/acme/messages.py 2020-06-02 19:12:31.000000000 +0200 +++ new/acme-1.6.0/acme/messages.py 2020-07-07 19:13:19.000000000 +0200 @@ -566,9 +566,11 @@ class Order(ResourceBody): """Order Resource Body. - :ivar list of .Identifier: List of identifiers for the certificate. + :ivar identifiers: List of identifiers for the certificate. + :vartype identifiers: `list` of `.Identifier` :ivar acme.messages.Status status: - :ivar list of str authorizations: URLs of authorizations. + :ivar authorizations: URLs of authorizations. + :vartype authorizations: `list` of `str` :ivar str certificate: URL to download certificate as a fullchain PEM. :ivar str finalize: URL to POST to to request issuance once all authorizations have "valid" status. @@ -593,15 +595,20 @@ :ivar acme.messages.Order body: :ivar str csr_pem: The CSR this Order will be finalized with. - :ivar list of acme.messages.AuthorizationResource authorizations: - Fully-fetched AuthorizationResource objects. + :ivar authorizations: Fully-fetched AuthorizationResource objects. + :vartype authorizations: `list` of `acme.messages.AuthorizationResource` :ivar str fullchain_pem: The fetched contents of the certificate URL produced once the order was finalized, if it's present. + :ivar alternative_fullchains_pem: The fetched contents of alternative certificate + chain URLs produced once the order was finalized, if present and requested during + finalization. + :vartype alternative_fullchains_pem: `list` of `str` """ body = jose.Field('body', decoder=Order.from_json) csr_pem = jose.Field('csr_pem', omitempty=True) authorizations = jose.Field('authorizations') fullchain_pem = jose.Field('fullchain_pem', omitempty=True) + alternative_fullchains_pem = jose.Field('alternative_fullchains_pem', omitempty=True) @Directory.register class NewOrder(Order): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/acme-1.5.0/acme.egg-info/PKG-INFO new/acme-1.6.0/acme.egg-info/PKG-INFO --- old/acme-1.5.0/acme.egg-info/PKG-INFO 2020-06-02 19:12:54.000000000 +0200 +++ new/acme-1.6.0/acme.egg-info/PKG-INFO 2020-07-07 19:13:32.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: acme -Version: 1.5.0 +Version: 1.6.0 Summary: ACME protocol implementation in Python Home-page: https://github.com/letsencrypt/letsencrypt Author: Certbot Project diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/acme-1.5.0/acme.egg-info/requires.txt new/acme-1.6.0/acme.egg-info/requires.txt --- old/acme-1.5.0/acme.egg-info/requires.txt 2020-06-02 19:12:54.000000000 +0200 +++ new/acme-1.6.0/acme.egg-info/requires.txt 2020-07-07 19:13:32.000000000 +0200 @@ -1,6 +1,6 @@ cryptography>=1.2.3 josepy>=1.1.0 -PyOpenSSL>=0.13.1 +PyOpenSSL>=0.15.1 pyrfc3339 pytz requests[security]>=2.6.0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/acme-1.5.0/setup.py new/acme-1.6.0/setup.py --- old/acme-1.5.0/setup.py 2020-06-02 19:12:35.000000000 +0200 +++ new/acme-1.6.0/setup.py 2020-07-07 19:13:23.000000000 +0200 @@ -1,4 +1,4 @@ -from distutils.version import StrictVersion +from distutils.version import LooseVersion import sys from setuptools import __version__ as setuptools_version @@ -6,7 +6,7 @@ from setuptools import setup from setuptools.command.test import test as TestCommand -version = '1.5.0' +version = '1.6.0' # Please update tox.ini when modifying dependency version requirements install_requires = [ @@ -17,8 +17,8 @@ # 1.1.0+ is required to avoid the warnings described at # https://github.com/certbot/josepy/issues/13. 'josepy>=1.1.0', - # Connection.set_tlsext_host_name (>=0.13) - 'PyOpenSSL>=0.13.1', + # Connection.set_tlsext_host_name (>=0.13) + matching Xenial requirements (>=0.15.1) + 'PyOpenSSL>=0.15.1', 'pyrfc3339', 'pytz', 'requests[security]>=2.6.0', # security extras added in 2.4.1 @@ -27,7 +27,7 @@ 'six>=1.9.0', # needed for python_2_unicode_compatible ] -setuptools_known_environment_markers = (StrictVersion(setuptools_version) >= StrictVersion('36.2')) +setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2')) if setuptools_known_environment_markers: install_requires.append('mock ; python_version < "3.3"') elif 'bdist_wheel' in sys.argv[1:]: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/acme-1.5.0/tests/client_test.py new/acme-1.6.0/tests/client_test.py --- old/acme-1.5.0/tests/client_test.py 2020-06-02 19:12:31.000000000 +0200 +++ new/acme-1.6.0/tests/client_test.py 2020-07-07 19:13:19.000000000 +0200 @@ -263,7 +263,7 @@ with mock.patch('acme.client.ClientV2') as mock_client: client = self._init() client.finalize_order(mock_orderr, mock_deadline) - mock_client().finalize_order.assert_called_once_with(mock_orderr, mock_deadline) + mock_client().finalize_order.assert_called_once_with(mock_orderr, mock_deadline, False) def test_revoke(self): self.response.json.return_value = DIRECTORY_V1.to_json() @@ -842,6 +842,32 @@ deadline = datetime.datetime.now() - datetime.timedelta(seconds=60) self.assertRaises(errors.TimeoutError, self.client.finalize_order, self.orderr, deadline) + def test_finalize_order_alt_chains(self): + updated_order = self.order.update( + certificate='https://www.letsencrypt-demo.org/acme/cert/', + ) + updated_orderr = self.orderr.update(body=updated_order, + fullchain_pem=CERT_SAN_PEM, + alternative_fullchains_pem=[CERT_SAN_PEM, + CERT_SAN_PEM]) + self.response.json.return_value = updated_order.to_json() + self.response.text = CERT_SAN_PEM + self.response.headers['Link'] ='<https://example.com/acme/cert/1>;rel="alternate", ' + \ + '<https://exaple.com/dir>;rel="index", ' + \ + '<https://example.com/acme/cert/2>;title="foo";rel="alternate"' + + deadline = datetime.datetime(9999, 9, 9) + resp = self.client.finalize_order(self.orderr, deadline, fetch_alternative_chains=True) + self.net.post.assert_any_call('https://example.com/acme/cert/1', + mock.ANY, acme_version=2, new_nonce_url=mock.ANY) + self.net.post.assert_any_call('https://example.com/acme/cert/2', + mock.ANY, acme_version=2, new_nonce_url=mock.ANY) + self.assertEqual(resp, updated_orderr) + + del self.response.headers['Link'] + resp = self.client.finalize_order(self.orderr, deadline, fetch_alternative_chains=True) + self.assertEqual(resp, updated_orderr.update(alternative_fullchains_pem=[])) + def test_revoke(self): self.client.revoke(messages_test.CERT, self.rsn) self.net.post.assert_called_once_with(
