Skip to content

Commit

Permalink
Allow _acme-challenge as a zone (#5707)
Browse files Browse the repository at this point in the history
* Allow _acme-challenge as a zone

Like described here:
https://github.com/lukas2511/dehydrated/wiki/example-dns-01-nsupdate-script

Not using this patch may be an issue if the parent zone has been (where a wildcard certificate has been requested.) signed by DNSSEC.

Please consider this also for inclusion before dns-01 will be allowed for wildcards.

* Update dns_rfc2136.py

forgot one domain_name reference

* Update dns_rfc2136.py

moved domain up & added assignment.

* Update dns_rfc2136_test.py

tests adjusted to new calls.

* Update dns_rfc2136_test.py

Forgot on DOMAIN...

* Update dns_rfc2136_test.py

* Update dns_rfc2136.py

pydoc updates.

* Update dns_rfc2136.py
  • Loading branch information
noci2012 authored and bmw committed Mar 20, 2018
1 parent 41ce108 commit c0dc31f
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 22 deletions.
26 changes: 12 additions & 14 deletions certbot-dns-rfc2136/certbot_dns_rfc2136/dns_rfc2136.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,11 @@ def _setup_credentials(self):
self._validate_algorithm
)

def _perform(self, domain, validation_name, validation):
self._get_rfc2136_client().add_txt_record(domain, validation_name, validation, self.ttl)
def _perform(self, _domain, validation_name, validation):
self._get_rfc2136_client().add_txt_record(validation_name, validation, self.ttl)

def _cleanup(self, domain, validation_name, validation):
self._get_rfc2136_client().del_txt_record(domain, validation_name, validation)
def _cleanup(self, _domain, validation_name, validation):
self._get_rfc2136_client().del_txt_record(validation_name, validation)

def _get_rfc2136_client(self):
return _RFC2136Client(self.credentials.conf('server'),
Expand All @@ -95,18 +95,17 @@ def __init__(self, server, key_name, key_secret, key_algorithm):
})
self.algorithm = key_algorithm

def add_txt_record(self, domain_name, record_name, record_content, record_ttl):
def add_txt_record(self, record_name, record_content, record_ttl):
"""
Add a TXT record using the supplied information.
:param str domain: The domain to use to find the closest SOA.
:param str record_name: The record name (typically beginning with '_acme-challenge.').
:param str record_content: The record content (typically the challenge validation).
:param int record_ttl: The record TTL (number of seconds that the record may be cached).
:raises certbot.errors.PluginError: if an error occurs communicating with the DNS server
"""

domain = self._find_domain(domain_name)
domain = self._find_domain(record_name)

n = dns.name.from_text(record_name)
o = dns.name.from_text(domain)
Expand All @@ -131,18 +130,17 @@ def add_txt_record(self, domain_name, record_name, record_content, record_ttl):
raise errors.PluginError('Received response from server: {0}'
.format(dns.rcode.to_text(rcode)))

def del_txt_record(self, domain_name, record_name, record_content):
def del_txt_record(self, record_name, record_content):
"""
Delete a TXT record using the supplied information.
:param str domain: The domain to use to find the closest SOA.
:param str record_name: The record name (typically beginning with '_acme-challenge.').
:param str record_content: The record content (typically the challenge validation).
:param int record_ttl: The record TTL (number of seconds that the record may be cached).
:raises certbot.errors.PluginError: if an error occurs communicating with the DNS server
"""

domain = self._find_domain(domain_name)
domain = self._find_domain(record_name)

n = dns.name.from_text(record_name)
o = dns.name.from_text(domain)
Expand All @@ -167,25 +165,25 @@ def del_txt_record(self, domain_name, record_name, record_content):
raise errors.PluginError('Received response from server: {0}'
.format(dns.rcode.to_text(rcode)))

def _find_domain(self, domain_name):
def _find_domain(self, record_name):
"""
Find the closest domain with an SOA record for a given domain name.
:param str domain_name: The domain name for which to find the closest SOA record.
:param str record_name: The record name for which to find the closest SOA record.
:returns: The domain, if found.
:rtype: str
:raises certbot.errors.PluginError: if no SOA record can be found.
"""

domain_name_guesses = dns_common.base_domain_name_guesses(domain_name)
domain_name_guesses = dns_common.base_domain_name_guesses(record_name)

# Loop through until we find an authoritative SOA record
for guess in domain_name_guesses:
if self._query_soa(guess):
return guess

raise errors.PluginError('Unable to determine base domain for {0} using names: {1}.'
.format(domain_name, domain_name_guesses))
.format(record_name, domain_name_guesses))

def _query_soa(self, domain_name):
"""
Expand Down
16 changes: 8 additions & 8 deletions certbot-dns-rfc2136/certbot_dns_rfc2136/dns_rfc2136_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,15 @@ def setUp(self):
def test_perform(self):
self.auth.perform([self.achall])

expected = [mock.call.add_txt_record(DOMAIN, '_acme-challenge.'+DOMAIN, mock.ANY, mock.ANY)]
expected = [mock.call.add_txt_record('_acme-challenge.'+DOMAIN, mock.ANY, mock.ANY)]
self.assertEqual(expected, self.mock_client.mock_calls)

def test_cleanup(self):
# _attempt_cleanup | pylint: disable=protected-access
self.auth._attempt_cleanup = True
self.auth.cleanup([self.achall])

expected = [mock.call.del_txt_record(DOMAIN, '_acme-challenge.'+DOMAIN, mock.ANY)]
expected = [mock.call.del_txt_record('_acme-challenge.'+DOMAIN, mock.ANY)]
self.assertEqual(expected, self.mock_client.mock_calls)

def test_invalid_algorithm_raises(self):
Expand Down Expand Up @@ -82,7 +82,7 @@ def test_add_txt_record(self, query_mock):
# _find_domain | pylint: disable=protected-access
self.rfc2136_client._find_domain = mock.MagicMock(return_value="example.com")

self.rfc2136_client.add_txt_record(DOMAIN, "bar", "baz", 42)
self.rfc2136_client.add_txt_record("bar", "baz", 42)

query_mock.assert_called_with(mock.ANY, SERVER)
self.assertTrue("bar. 42 IN TXT \"baz\"" in str(query_mock.call_args[0][0]))
Expand All @@ -96,7 +96,7 @@ def test_add_txt_record_wraps_errors(self, query_mock):
self.assertRaises(
errors.PluginError,
self.rfc2136_client.add_txt_record,
DOMAIN, "bar", "baz", 42)
"bar", "baz", 42)

@mock.patch("dns.query.tcp")
def test_add_txt_record_server_error(self, query_mock):
Expand All @@ -107,15 +107,15 @@ def test_add_txt_record_server_error(self, query_mock):
self.assertRaises(
errors.PluginError,
self.rfc2136_client.add_txt_record,
DOMAIN, "bar", "baz", 42)
"bar", "baz", 42)

@mock.patch("dns.query.tcp")
def test_del_txt_record(self, query_mock):
query_mock.return_value.rcode.return_value = dns.rcode.NOERROR
# _find_domain | pylint: disable=protected-access
self.rfc2136_client._find_domain = mock.MagicMock(return_value="example.com")

self.rfc2136_client.del_txt_record(DOMAIN, "bar", "baz")
self.rfc2136_client.del_txt_record("bar", "baz")

query_mock.assert_called_with(mock.ANY, SERVER)
self.assertTrue("bar. 0 NONE TXT \"baz\"" in str(query_mock.call_args[0][0]))
Expand All @@ -129,7 +129,7 @@ def test_del_txt_record_wraps_errors(self, query_mock):
self.assertRaises(
errors.PluginError,
self.rfc2136_client.del_txt_record,
DOMAIN, "bar", "baz")
"bar", "baz")

@mock.patch("dns.query.tcp")
def test_del_txt_record_server_error(self, query_mock):
Expand All @@ -140,7 +140,7 @@ def test_del_txt_record_server_error(self, query_mock):
self.assertRaises(
errors.PluginError,
self.rfc2136_client.del_txt_record,
DOMAIN, "bar", "baz")
"bar", "baz")

def test_find_domain(self):
# _query_soa | pylint: disable=protected-access
Expand Down

0 comments on commit c0dc31f

Please sign in to comment.