Merge tag 'upstream/1.10.1'
Upstream version 1.10.1
Harlan Lieberman-Berg
2 years ago
0 | 0 | Metadata-Version: 2.1 |
1 | 1 | Name: certbot-dns-rfc2136 |
2 | Version: 1.3.0 | |
2 | Version: 1.10.1 | |
3 | 3 | Summary: RFC 2136 DNS Authenticator plugin for Certbot |
4 | 4 | Home-page: https://github.com/certbot/certbot |
5 | 5 | Author: Certbot Project |
16 | 16 | Classifier: Programming Language :: Python :: 2 |
17 | 17 | Classifier: Programming Language :: Python :: 2.7 |
18 | 18 | Classifier: Programming Language :: Python :: 3 |
19 | Classifier: Programming Language :: Python :: 3.5 | |
20 | 19 | Classifier: Programming Language :: Python :: 3.6 |
21 | 20 | Classifier: Programming Language :: Python :: 3.7 |
22 | 21 | Classifier: Programming Language :: Python :: 3.8 |
22 | Classifier: Programming Language :: Python :: 3.9 | |
23 | 23 | Classifier: Topic :: Internet :: WWW/HTTP |
24 | 24 | Classifier: Topic :: Security |
25 | 25 | Classifier: Topic :: System :: Installation/Setup |
26 | 26 | Classifier: Topic :: System :: Networking |
27 | 27 | Classifier: Topic :: System :: Systems Administration |
28 | 28 | Classifier: Topic :: Utilities |
29 | Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.* | |
29 | Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.* | |
30 | 30 | Provides-Extra: docs |
98 | 98 | This configuration limits the scope of the TSIG key to just be able to |
99 | 99 | add and remove TXT records for one specific host for the purpose of |
100 | 100 | completing the ``dns-01`` challenge. If your version of BIND doesn't |
101 | support the | |
102 | `update-policy <http://www.zytrax.com/books/dns/ch7/xfer.html#update-policy>`_ | |
103 | directive then you can use the less-secure | |
104 | `allow-update <http://www.zytrax.com/books/dns/ch7/xfer.html#allow-update>`_ | |
105 | directive instead. | |
101 | support the ``update-policy`` directive, then you can use the less-secure | |
102 | ``allow-update`` directive instead. `See the BIND documentation | |
103 | <https://bind9.readthedocs.io/en/latest/reference.html#dynamic-update-policies>`_ | |
104 | for details. | |
106 | 105 | |
107 | 106 | Examples |
108 | 107 | -------- |
0 | # type: ignore | |
1 | # pylint: disable=no-member | |
2 | # Many attributes of dnspython are now dynamically defined which causes both | |
3 | # mypy and pylint to error about accessing attributes they think do not exist. | |
4 | # This is the case even in up-to-date versions of mypy and pylint which as of | |
5 | # writing this are 0.790 and 2.6.0 respectively. This problem may be fixed in | |
6 | # dnspython 2.1.0. See https://github.com/rthalley/dnspython/issues/598. For | |
7 | # now, let's disable these checks. This is done at the very top of the file | |
8 | # like this because "type: ignore" must be the first line in the file to be | |
9 | # respected by mypy. | |
0 | 10 | """DNS Authenticator using RFC 2136 Dynamic Updates.""" |
1 | 11 | import logging |
2 | 12 | |
17 | 27 | |
18 | 28 | logger = logging.getLogger(__name__) |
19 | 29 | |
30 | DEFAULT_NETWORK_TIMEOUT = 45 | |
20 | 31 | |
21 | 32 | @zope.interface.implementer(interfaces.IAuthenticator) |
22 | 33 | @zope.interface.provider(interfaces.IPluginFactory) |
90 | 101 | """ |
91 | 102 | Encapsulates all communication with the target DNS server. |
92 | 103 | """ |
93 | def __init__(self, server, port, key_name, key_secret, key_algorithm): | |
104 | def __init__(self, server, port, key_name, key_secret, key_algorithm, | |
105 | timeout=DEFAULT_NETWORK_TIMEOUT): | |
94 | 106 | self.server = server |
95 | 107 | self.port = port |
96 | 108 | self.keyring = dns.tsigkeyring.from_text({ |
97 | 109 | key_name: key_secret |
98 | 110 | }) |
99 | 111 | self.algorithm = key_algorithm |
112 | self._default_timeout = timeout | |
100 | 113 | |
101 | 114 | def add_txt_record(self, record_name, record_content, record_ttl): |
102 | 115 | """ |
121 | 134 | update.add(rel, record_ttl, dns.rdatatype.TXT, record_content) |
122 | 135 | |
123 | 136 | try: |
124 | response = dns.query.tcp(update, self.server, port=self.port) | |
137 | response = dns.query.tcp(update, self.server, self._default_timeout, self.port) | |
125 | 138 | except Exception as e: |
126 | 139 | raise errors.PluginError('Encountered error adding TXT record: {0}' |
127 | 140 | .format(e)) |
156 | 169 | update.delete(rel, dns.rdatatype.TXT, record_content) |
157 | 170 | |
158 | 171 | try: |
159 | response = dns.query.tcp(update, self.server, port=self.port) | |
172 | response = dns.query.tcp(update, self.server, self._default_timeout, self.port) | |
160 | 173 | except Exception as e: |
161 | 174 | raise errors.PluginError('Encountered error deleting TXT record: {0}' |
162 | 175 | .format(e)) |
206 | 219 | |
207 | 220 | try: |
208 | 221 | try: |
209 | response = dns.query.tcp(request, self.server, port=self.port) | |
210 | except OSError as e: | |
222 | response = dns.query.tcp(request, self.server, self._default_timeout, self.port) | |
223 | except (OSError, dns.exception.Timeout) as e: | |
211 | 224 | logger.debug('TCP query failed, fallback to UDP: %s', e) |
212 | response = dns.query.udp(request, self.server, port=self.port) | |
225 | response = dns.query.udp(request, self.server, self._default_timeout, self.port) | |
213 | 226 | rcode = response.rcode() |
214 | 227 | |
215 | 228 | # Authoritative Answer bit should be set |
0 | 0 | Metadata-Version: 2.1 |
1 | 1 | Name: certbot-dns-rfc2136 |
2 | Version: 1.3.0 | |
2 | Version: 1.10.1 | |
3 | 3 | Summary: RFC 2136 DNS Authenticator plugin for Certbot |
4 | 4 | Home-page: https://github.com/certbot/certbot |
5 | 5 | Author: Certbot Project |
16 | 16 | Classifier: Programming Language :: Python :: 2 |
17 | 17 | Classifier: Programming Language :: Python :: 2.7 |
18 | 18 | Classifier: Programming Language :: Python :: 3 |
19 | Classifier: Programming Language :: Python :: 3.5 | |
20 | 19 | Classifier: Programming Language :: Python :: 3.6 |
21 | 20 | Classifier: Programming Language :: Python :: 3.7 |
22 | 21 | Classifier: Programming Language :: Python :: 3.8 |
22 | Classifier: Programming Language :: Python :: 3.9 | |
23 | 23 | Classifier: Topic :: Internet :: WWW/HTTP |
24 | 24 | Classifier: Topic :: Security |
25 | 25 | Classifier: Topic :: System :: Installation/Setup |
26 | 26 | Classifier: Topic :: System :: Networking |
27 | 27 | Classifier: Topic :: System :: Systems Administration |
28 | 28 | Classifier: Topic :: Utilities |
29 | Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.* | |
29 | Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.* | |
30 | 30 | Provides-Extra: docs |
0 | dnspython | |
1 | setuptools | |
2 | zope.interface | |
0 | 3 | acme>=0.29.0 |
1 | 4 | certbot>=1.1.0 |
2 | dnspython | |
5 | ||
6 | [:python_version < "3.3"] | |
3 | 7 | mock |
4 | setuptools | |
5 | zope.interface | |
6 | 8 | |
7 | 9 | [docs] |
8 | 10 | Sphinx>=1.0 |
92 | 92 | # a list of builtin themes. |
93 | 93 | # |
94 | 94 | |
95 | # http://docs.readthedocs.org/en/latest/theme.html#how-do-i-use-this-locally-and-on-read-the-docs | |
95 | # https://docs.readthedocs.io/en/stable/faq.html#i-want-to-use-the-read-the-docs-theme-locally | |
96 | 96 | # on_rtd is whether we are on readthedocs.org |
97 | 97 | on_rtd = os.environ.get('READTHEDOCS', None) == 'True' |
98 | 98 | if not on_rtd: # only import and set the theme if we're building docs locally |
21 | 21 | echo.Sphinx directory to PATH. |
22 | 22 | echo. |
23 | 23 | echo.If you don't have Sphinx installed, grab it from |
24 | echo.http://sphinx-doc.org/ | |
24 | echo.https://www.sphinx-doc.org/ | |
25 | 25 | exit /b 1 |
26 | 26 | ) |
27 | 27 |
0 | from distutils.version import LooseVersion | |
1 | import os | |
0 | 2 | import sys |
1 | 3 | |
4 | from setuptools import __version__ as setuptools_version | |
2 | 5 | from setuptools import find_packages |
3 | 6 | from setuptools import setup |
4 | from setuptools.command.test import test as TestCommand | |
5 | 7 | |
6 | version = '1.3.0' | |
8 | version = '1.10.1' | |
7 | 9 | |
8 | 10 | # Remember to update local-oldest-requirements.txt when changing the minimum |
9 | 11 | # acme/certbot version. |
10 | 12 | install_requires = [ |
11 | 'acme>=0.29.0', | |
12 | 'certbot>=1.1.0', | |
13 | 13 | 'dnspython', |
14 | 'mock', | |
15 | 14 | 'setuptools', |
16 | 15 | 'zope.interface', |
17 | 16 | ] |
17 | ||
18 | if not os.environ.get('SNAP_BUILD'): | |
19 | install_requires.extend([ | |
20 | 'acme>=0.29.0', | |
21 | 'certbot>=1.1.0', | |
22 | ]) | |
23 | elif 'bdist_wheel' in sys.argv[1:]: | |
24 | raise RuntimeError('Unset SNAP_BUILD when building wheels ' | |
25 | 'to include certbot dependencies.') | |
26 | if os.environ.get('SNAP_BUILD'): | |
27 | install_requires.append('packaging') | |
28 | ||
29 | setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2')) | |
30 | if setuptools_known_environment_markers: | |
31 | install_requires.append('mock ; python_version < "3.3"') | |
32 | elif 'bdist_wheel' in sys.argv[1:]: | |
33 | raise RuntimeError('Error, you are trying to build certbot wheels using an old version ' | |
34 | 'of setuptools. Version 36.2+ of setuptools is required.') | |
35 | elif sys.version_info < (3,3): | |
36 | install_requires.append('mock') | |
18 | 37 | |
19 | 38 | docs_extras = [ |
20 | 39 | 'Sphinx>=1.0', # autodoc_member_order = 'bysource', autodoc_default_flags |
21 | 40 | 'sphinx_rtd_theme', |
22 | 41 | ] |
23 | ||
24 | class PyTest(TestCommand): | |
25 | user_options = [] | |
26 | ||
27 | def initialize_options(self): | |
28 | TestCommand.initialize_options(self) | |
29 | self.pytest_args = '' | |
30 | ||
31 | def run_tests(self): | |
32 | import shlex | |
33 | # import here, cause outside the eggs aren't loaded | |
34 | import pytest | |
35 | errno = pytest.main(shlex.split(self.pytest_args)) | |
36 | sys.exit(errno) | |
37 | 42 | |
38 | 43 | setup( |
39 | 44 | name='certbot-dns-rfc2136', |
43 | 48 | author="Certbot Project", |
44 | 49 | author_email='client-dev@letsencrypt.org', |
45 | 50 | license='Apache License 2.0', |
46 | python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*', | |
51 | python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*', | |
47 | 52 | classifiers=[ |
48 | 53 | 'Development Status :: 5 - Production/Stable', |
49 | 54 | 'Environment :: Plugins', |
54 | 59 | 'Programming Language :: Python :: 2', |
55 | 60 | 'Programming Language :: Python :: 2.7', |
56 | 61 | 'Programming Language :: Python :: 3', |
57 | 'Programming Language :: Python :: 3.5', | |
58 | 62 | 'Programming Language :: Python :: 3.6', |
59 | 63 | 'Programming Language :: Python :: 3.7', |
60 | 64 | 'Programming Language :: Python :: 3.8', |
65 | 'Programming Language :: Python :: 3.9', | |
61 | 66 | 'Topic :: Internet :: WWW/HTTP', |
62 | 67 | 'Topic :: Security', |
63 | 68 | 'Topic :: System :: Installation/Setup', |
77 | 82 | 'dns-rfc2136 = certbot_dns_rfc2136._internal.dns_rfc2136:Authenticator', |
78 | 83 | ], |
79 | 84 | }, |
80 | tests_require=["pytest"], | |
81 | test_suite='certbot_dns_rfc2136', | |
82 | cmdclass={"test": PyTest}, | |
83 | 85 | ) |
4 | 4 | import dns.flags |
5 | 5 | import dns.rcode |
6 | 6 | import dns.tsig |
7 | import mock | |
7 | try: | |
8 | import mock | |
9 | except ImportError: # pragma: no cover | |
10 | from unittest import mock # type: ignore | |
8 | 11 | |
9 | 12 | from certbot import errors |
10 | 13 | from certbot.compat import os |
17 | 20 | NAME = 'a-tsig-key.' |
18 | 21 | SECRET = 'SSB3b25kZXIgd2hvIHdpbGwgYm90aGVyIHRvIGRlY29kZSB0aGlzIHRleHQK' |
19 | 22 | VALID_CONFIG = {"rfc2136_server": SERVER, "rfc2136_name": NAME, "rfc2136_secret": SECRET} |
20 | ||
23 | TIMEOUT = 45 | |
21 | 24 | |
22 | 25 | class AuthenticatorTest(test_util.TempDirTestCase, dns_test_common.BaseAuthenticatorTest): |
23 | 26 | |
74 | 77 | def setUp(self): |
75 | 78 | from certbot_dns_rfc2136._internal.dns_rfc2136 import _RFC2136Client |
76 | 79 | |
77 | self.rfc2136_client = _RFC2136Client(SERVER, PORT, NAME, SECRET, dns.tsig.HMAC_MD5) | |
80 | self.rfc2136_client = _RFC2136Client(SERVER, PORT, NAME, SECRET, dns.tsig.HMAC_MD5, | |
81 | TIMEOUT) | |
78 | 82 | |
79 | 83 | @mock.patch("dns.query.tcp") |
80 | 84 | def test_add_txt_record(self, query_mock): |
84 | 88 | |
85 | 89 | self.rfc2136_client.add_txt_record("bar", "baz", 42) |
86 | 90 | |
87 | query_mock.assert_called_with(mock.ANY, SERVER, port=PORT) | |
91 | query_mock.assert_called_with(mock.ANY, SERVER, TIMEOUT, PORT) | |
88 | 92 | self.assertTrue("bar. 42 IN TXT \"baz\"" in str(query_mock.call_args[0][0])) |
89 | 93 | |
90 | 94 | @mock.patch("dns.query.tcp") |
117 | 121 | |
118 | 122 | self.rfc2136_client.del_txt_record("bar", "baz") |
119 | 123 | |
120 | query_mock.assert_called_with(mock.ANY, SERVER, port=PORT) | |
124 | query_mock.assert_called_with(mock.ANY, SERVER, TIMEOUT, PORT) | |
121 | 125 | self.assertTrue("bar. 0 NONE TXT \"baz\"" in str(query_mock.call_args[0][0])) |
122 | 126 | |
123 | 127 | @mock.patch("dns.query.tcp") |
149 | 153 | # _find_domain | pylint: disable=protected-access |
150 | 154 | domain = self.rfc2136_client._find_domain('foo.bar.'+DOMAIN) |
151 | 155 | |
152 | self.assertTrue(domain == DOMAIN) | |
156 | self.assertEqual(domain, DOMAIN) | |
153 | 157 | |
154 | 158 | def test_find_domain_wraps_errors(self): |
155 | 159 | # _query_soa | pylint: disable=protected-access |
169 | 173 | # _query_soa | pylint: disable=protected-access |
170 | 174 | result = self.rfc2136_client._query_soa(DOMAIN) |
171 | 175 | |
172 | query_mock.assert_called_with(mock.ANY, SERVER, port=PORT) | |
176 | query_mock.assert_called_with(mock.ANY, SERVER, TIMEOUT, PORT) | |
173 | 177 | self.assertTrue(result) |
174 | 178 | |
175 | 179 | @mock.patch("dns.query.tcp") |
179 | 183 | # _query_soa | pylint: disable=protected-access |
180 | 184 | result = self.rfc2136_client._query_soa(DOMAIN) |
181 | 185 | |
182 | query_mock.assert_called_with(mock.ANY, SERVER, port=PORT) | |
186 | query_mock.assert_called_with(mock.ANY, SERVER, TIMEOUT, PORT) | |
183 | 187 | self.assertFalse(result) |
184 | 188 | |
185 | 189 | @mock.patch("dns.query.tcp") |
202 | 206 | # _query_soa | pylint: disable=protected-access |
203 | 207 | result = self.rfc2136_client._query_soa(DOMAIN) |
204 | 208 | |
205 | tcp_mock.assert_called_with(mock.ANY, SERVER, port=PORT) | |
206 | udp_mock.assert_called_with(mock.ANY, SERVER, port=PORT) | |
209 | tcp_mock.assert_called_with(mock.ANY, SERVER, TIMEOUT, PORT) | |
210 | udp_mock.assert_called_with(mock.ANY, SERVER, TIMEOUT, PORT) | |
207 | 211 | self.assertTrue(result) |
208 | 212 | |
209 | 213 |