Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/certbot/certbot.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/acme
diff options
context:
space:
mode:
authorBrad Warren <bmw@users.noreply.github.com>2017-01-31 03:55:54 +0300
committerGitHub <noreply@github.com>2017-01-31 03:55:54 +0300
commitbe5bcfe463d9649c350181fe1a84e9d513db1ff3 (patch)
tree7603ad81d46ccb0576160eca09b23520f3b5a0c9 /acme
parent240438eec73ad20c50db3bc242a0a229cabf8f66 (diff)
Remove optional dependencies (#4088)
* Stop using already_listening in standalone * remove already_listening * remove psutil entirely * fix #595 * Add basic perform test * make pep8 happy * Add test_perform_eacces * add _setup_perform_error * Add test_perform_unexpected_socket_error * add test_perform_eaddrinuse_no_retry * add test_perform_eaddrinuse_retry * cleanup tests * stop using dnspython * don't install dns extras in tox * remove dns extras from setup.py * Add simple_verify back to DNS response * remove dnspython from oldest tests
Diffstat (limited to 'acme')
-rw-r--r--acme/acme/challenges.py31
-rw-r--r--acme/acme/challenges_test.py49
-rw-r--r--acme/acme/dns_resolver.py45
-rw-r--r--acme/acme/dns_resolver_test.py77
-rw-r--r--acme/acme/test_util.py16
-rw-r--r--acme/acme/util.py18
-rw-r--r--acme/acme/util_test.py18
-rw-r--r--acme/setup.py6
8 files changed, 18 insertions, 242 deletions
diff --git a/acme/acme/challenges.py b/acme/acme/challenges.py
index 3bfc1e62f..83b9b9edd 100644
--- a/acme/acme/challenges.py
+++ b/acme/acme/challenges.py
@@ -9,7 +9,6 @@ from cryptography.hazmat.primitives import hashes
import OpenSSL
import requests
-from acme import dns_resolver
from acme import errors
from acme import crypto_util
from acme import fields
@@ -214,36 +213,24 @@ class DNS01Response(KeyAuthorizationChallengeResponse):
def simple_verify(self, chall, domain, account_public_key):
"""Simple verify.
+ This method no longer checks DNS records and is a simple wrapper
+ around `KeyAuthorizationChallengeResponse.verify`.
+
:param challenges.DNS01 chall: Corresponding challenge.
:param unicode domain: Domain name being verified.
:param JWK account_public_key: Public key for the key pair
being authorized.
- :returns: ``True`` iff validation with the TXT records resolved from a
- DNS server is successful.
+ :return: ``True`` iff verification of the key authorization was
+ successful.
:rtype: bool
"""
- if not self.verify(chall, account_public_key):
+ # pylint: disable=unused-argument
+ verified = self.verify(chall, account_public_key)
+ if not verified:
logger.debug("Verification of key authorization in response failed")
- return False
-
- validation_domain_name = chall.validation_domain_name(domain)
- validation = chall.validation(account_public_key)
- logger.debug("Verifying %s at %s...", chall.typ, validation_domain_name)
-
- try:
- txt_records = dns_resolver.txt_records_for_name(
- validation_domain_name)
- except errors.DependencyError:
- raise errors.DependencyError("Local validation for 'dns-01' "
- "challenges requires 'dnspython'")
- exists = validation in txt_records
- if not exists:
- logger.debug("Key authorization from response (%r) doesn't match "
- "any DNS response in %r", self.key_authorization,
- txt_records)
- return exists
+ return verified
@Challenge.register # pylint: disable=too-many-ancestors
diff --git a/acme/acme/challenges_test.py b/acme/acme/challenges_test.py
index 5ac07abdd..49e790102 100644
--- a/acme/acme/challenges_test.py
+++ b/acme/acme/challenges_test.py
@@ -10,7 +10,6 @@ from six.moves.urllib import parse as urllib_parse # pylint: disable=import-err
from acme import errors
from acme import jose
from acme import test_util
-from acme.dns_resolver import DNS_REQUIREMENT
CERT = test_util.load_comparable_cert('cert.pem')
KEY = jose.JWKRSA(key=test_util.load_rsa_private_key('rsa512_key.pem'))
@@ -92,7 +91,6 @@ class DNS01ResponseTest(unittest.TestCase):
from acme.challenges import DNS01
self.chall = DNS01(token=(b'x' * 16))
self.response = self.chall.response(KEY)
- self.records_for_name_path = "acme.dns_resolver.txt_records_for_name"
def test_to_partial_json(self):
self.assertEqual(self.jmsg, self.msg.to_partial_json())
@@ -105,45 +103,16 @@ class DNS01ResponseTest(unittest.TestCase):
from acme.challenges import DNS01Response
hash(DNS01Response.from_json(self.jmsg))
- def test_simple_verify_bad_key_authorization(self):
+ def test_simple_verify_failure(self):
key2 = jose.JWKRSA.load(test_util.load_vector('rsa256_key.pem'))
- self.response.simple_verify(self.chall, "local", key2.public_key())
-
- @mock.patch('acme.dns_resolver.DNS_AVAILABLE', False)
- def test_simple_verify_without_dns(self):
- self.assertRaises(
- errors.DependencyError, self.response.simple_verify,
- self.chall, 'local', KEY.public_key())
-
- @test_util.skip_unless(test_util.requirement_available(DNS_REQUIREMENT),
- "optional dependency dnspython is not available")
- def test_simple_verify_good_validation(self): # pragma: no cover
- with mock.patch(self.records_for_name_path) as mock_resolver:
- mock_resolver.return_value = [
- self.chall.validation(KEY.public_key())]
- self.assertTrue(self.response.simple_verify(
- self.chall, "local", KEY.public_key()))
- mock_resolver.assert_called_once_with(
- self.chall.validation_domain_name("local"))
-
- @test_util.skip_unless(test_util.requirement_available(DNS_REQUIREMENT),
- "optional dependency dnspython is not available")
- def test_simple_verify_good_validation_multitxts(self): # pragma: no cover
- with mock.patch(self.records_for_name_path) as mock_resolver:
- mock_resolver.return_value = [
- "!", self.chall.validation(KEY.public_key())]
- self.assertTrue(self.response.simple_verify(
- self.chall, "local", KEY.public_key()))
- mock_resolver.assert_called_once_with(
- self.chall.validation_domain_name("local"))
-
- @test_util.skip_unless(test_util.requirement_available(DNS_REQUIREMENT),
- "optional dependency dnspython is not available")
- def test_simple_verify_bad_validation(self): # pragma: no cover
- with mock.patch(self.records_for_name_path) as mock_resolver:
- mock_resolver.return_value = ["!"]
- self.assertFalse(self.response.simple_verify(
- self.chall, "local", KEY.public_key()))
+ public_key = key2.public_key()
+ verified = self.response.simple_verify(self.chall, "local", public_key)
+ self.assertFalse(verified)
+
+ def test_simple_verify_success(self):
+ public_key = KEY.public_key()
+ verified = self.response.simple_verify(self.chall, "local", public_key)
+ self.assertTrue(verified)
class DNS01Test(unittest.TestCase):
diff --git a/acme/acme/dns_resolver.py b/acme/acme/dns_resolver.py
deleted file mode 100644
index 2677d92ad..000000000
--- a/acme/acme/dns_resolver.py
+++ /dev/null
@@ -1,45 +0,0 @@
-"""DNS Resolver for ACME client.
-Required only for local validation of 'dns-01' challenges.
-"""
-import logging
-
-from acme import errors
-from acme import util
-
-DNS_REQUIREMENT = 'dnspython>=1.12'
-
-try:
- util.activate(DNS_REQUIREMENT)
- # pragma: no cover
- import dns.exception
- import dns.resolver
- DNS_AVAILABLE = True
-except errors.DependencyError: # pragma: no cover
- DNS_AVAILABLE = False
-
-
-logger = logging.getLogger(__name__)
-
-
-def txt_records_for_name(name):
- """Resolve the name and return the TXT records.
-
- :param unicode name: Domain name being verified.
-
- :returns: A list of txt records, if empty the name could not be resolved
- :rtype: list of unicode
-
- """
- if not DNS_AVAILABLE:
- raise errors.DependencyError(
- '{0} is required to use this function'.format(DNS_REQUIREMENT))
- try:
- dns_response = dns.resolver.query(name, 'TXT')
- except dns.resolver.NXDOMAIN as error:
- return []
- except dns.exception.DNSException as error:
- logger.error("Error resolving %s: %s", name, str(error))
- return []
-
- return [txt_rec.decode("utf-8") for rdata in dns_response
- for txt_rec in rdata.strings]
diff --git a/acme/acme/dns_resolver_test.py b/acme/acme/dns_resolver_test.py
deleted file mode 100644
index 2e2edd0e7..000000000
--- a/acme/acme/dns_resolver_test.py
+++ /dev/null
@@ -1,77 +0,0 @@
-"""Tests for acme.dns_resolver."""
-import unittest
-
-import mock
-from six.moves import reload_module # pylint: disable=import-error
-
-from acme import errors
-from acme import test_util
-from acme.dns_resolver import DNS_REQUIREMENT
-
-
-if test_util.requirement_available(DNS_REQUIREMENT):
- import dns
-
-
-def create_txt_response(name, txt_records):
- """
- Returns an RRSet containing the 'txt_records' as the result of a DNS
- query for 'name'.
-
- This takes advantage of the fact that an Answer object mostly behaves
- like an RRset.
- """
- return dns.rrset.from_text_list(name, 60, "IN", "TXT", txt_records)
-
-
-class TxtRecordsForNameTest(unittest.TestCase):
- """Tests for acme.dns_resolver.txt_records_for_name."""
- @classmethod
- def _call(cls, *args, **kwargs):
- from acme.dns_resolver import txt_records_for_name
- return txt_records_for_name(*args, **kwargs)
-
-
-@test_util.skip_unless(test_util.requirement_available(DNS_REQUIREMENT),
- "optional dependency dnspython is not available")
-class TxtRecordsForNameWithDnsTest(TxtRecordsForNameTest):
- """Tests for acme.dns_resolver.txt_records_for_name with dns."""
- @mock.patch("acme.dns_resolver.dns.resolver.query")
- def test_txt_records_for_name_with_single_response(self, mock_dns):
- mock_dns.return_value = create_txt_response('name', ['response'])
- self.assertEqual(['response'], self._call('name'))
-
- @mock.patch("acme.dns_resolver.dns.resolver.query")
- def test_txt_records_for_name_with_multiple_responses(self, mock_dns):
- mock_dns.return_value = create_txt_response(
- 'name', ['response1', 'response2'])
- self.assertEqual(['response1', 'response2'], self._call('name'))
-
- @mock.patch("acme.dns_resolver.dns.resolver.query")
- def test_txt_records_for_name_domain_not_found(self, mock_dns):
- mock_dns.side_effect = dns.resolver.NXDOMAIN
- self.assertEquals([], self._call('name'))
-
- @mock.patch("acme.dns_resolver.dns.resolver.query")
- def test_txt_records_for_name_domain_other_error(self, mock_dns):
- mock_dns.side_effect = dns.exception.DNSException
- self.assertEquals([], self._call('name'))
-
-
-class TxtRecordsForNameWithoutDnsTest(TxtRecordsForNameTest):
- """Tests for acme.dns_resolver.txt_records_for_name without dns."""
- def setUp(self):
- from acme import dns_resolver
- dns_resolver.DNS_AVAILABLE = False
-
- def tearDown(self):
- from acme import dns_resolver
- reload_module(dns_resolver)
-
- def test_exception_raised(self):
- self.assertRaises(
- errors.DependencyError, self._call, "example.org")
-
-
-if __name__ == '__main__':
- unittest.main() # pragma: no cover
diff --git a/acme/acme/test_util.py b/acme/acme/test_util.py
index ba968511f..0f5763682 100644
--- a/acme/acme/test_util.py
+++ b/acme/acme/test_util.py
@@ -11,9 +11,7 @@ from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
import OpenSSL
-from acme import errors
from acme import jose
-from acme import util
def vector_path(*names):
@@ -78,20 +76,6 @@ def load_pyopenssl_private_key(*names):
return OpenSSL.crypto.load_privatekey(loader, load_vector(*names))
-def requirement_available(requirement):
- """Checks if requirement can be imported.
-
- :rtype: bool
- :returns: ``True`` iff requirement can be imported
-
- """
- try:
- util.activate(requirement)
- except errors.DependencyError: # pragma: no cover
- return False
- return True # pragma: no cover
-
-
def skip_unless(condition, reason): # pragma: no cover
"""Skip tests unless a condition holds.
diff --git a/acme/acme/util.py b/acme/acme/util.py
index ac445b271..1fff89a9e 100644
--- a/acme/acme/util.py
+++ b/acme/acme/util.py
@@ -1,25 +1,7 @@
"""ACME utilities."""
-import pkg_resources
import six
-from acme import errors
-
def map_keys(dikt, func):
"""Map dictionary keys."""
return dict((func(key), value) for key, value in six.iteritems(dikt))
-
-
-def activate(requirement):
- """Make requirement importable.
-
- :param str requirement: the distribution and version to activate
-
- :raises acme.errors.DependencyError: if cannot activate requirement
-
- """
- try:
- for distro in pkg_resources.require(requirement): # pylint: disable=not-callable
- distro.activate()
- except (pkg_resources.DistributionNotFound, pkg_resources.VersionConflict):
- raise errors.DependencyError('{0} is unavailable'.format(requirement))
diff --git a/acme/acme/util_test.py b/acme/acme/util_test.py
index ba6465409..00aa8b02d 100644
--- a/acme/acme/util_test.py
+++ b/acme/acme/util_test.py
@@ -1,8 +1,6 @@
"""Tests for acme.util."""
import unittest
-from acme import errors
-
class MapKeysTest(unittest.TestCase):
"""Tests for acme.util.map_keys."""
@@ -14,21 +12,5 @@ class MapKeysTest(unittest.TestCase):
self.assertEqual({2: 2, 4: 4}, map_keys({1: 2, 3: 4}, lambda x: x + 1))
-class ActivateTest(unittest.TestCase):
- """Tests for acme.util.activate."""
-
- @classmethod
- def _call(cls, *args, **kwargs):
- from acme.util import activate
- return activate(*args, **kwargs)
-
- def test_failure(self):
- self.assertRaises(errors.DependencyError, self._call, 'acme>99.0.0')
-
- def test_success(self):
- self._call('acme')
- import acme as unused_acme
-
-
if __name__ == '__main__':
unittest.main() # pragma: no cover
diff --git a/acme/setup.py b/acme/setup.py
index 37b71368c..d05d814ad 100644
--- a/acme/setup.py
+++ b/acme/setup.py
@@ -33,11 +33,6 @@ if sys.version_info < (2, 7):
else:
install_requires.append('mock')
-# dnspython 1.12 is required to support both Python 2 and Python 3.
-dns_extras = [
- 'dnspython>=1.12',
-]
-
dev_extras = [
'nose',
'tox',
@@ -77,7 +72,6 @@ setup(
include_package_data=True,
install_requires=install_requires,
extras_require={
- 'dns': dns_extras,
'dev': dev_extras,
'docs': docs_extras,
},