Further adaptions

This commit is contained in:
Masin Al-Dujaili
2020-04-13 12:18:36 +02:00
parent f7aaab6bb0
commit 4aae0b9db3
5 changed files with 151 additions and 454 deletions

View File

@@ -0,0 +1,85 @@
"""
The `~certbot_dns_corenetworks.dns_corenetworks` plugin automates the process of
completing a ``dns-01`` challenge (`~acme.challenges.DNS01`) by creating, and
subsequently removing, TXT records using the Core Networks beta API.
Named Arguments
---------------
======================================== =====================================
``--dns-corenetworks-credentials`` Core Networks beta API credentials_
INI file. (Required)
``--dns-corenetworks-propagation-seconds`` The number of seconds to wait for DNS
to propagate before asking the ACME
server to verify the DNS record.
(Default: 120)
======================================== =====================================
Credentials
-----------
Use of this plugin requires a configuration file containing Core Networks beta API
credentials, obtained from your DNSimple
`System > Remote Users`.
.. code-block:: ini
:name: credentials.ini
:caption: Example credentials file:
# Core Networks API credentials used by Certbot
dns_corenetworks_username = mycorenetworksapiuser
dns_corenetworks_password = mysecretpassword
The path to this file can be provided interactively or using the
``--dns-corenetworks-credentials`` command-line argument. Certbot records the path
to this file for use during renewal, but does not store the file's contents.
.. caution::
You should protect these API credentials as you would a password. Users who
can read this file can use these credentials to issue arbitrary API calls on
your behalf. Users who can cause Certbot to run using these credentials can
complete a ``dns-01`` challenge to acquire new certificates or revoke
existing certificates for associated domains, even if those domains aren't
being managed by this server.
Certbot will emit a warning if it detects that the credentials file can be
accessed by other users on your system. The warning reads "Unsafe permissions
on credentials configuration file", followed by the path to the credentials
file. This warning will be emitted each time Certbot uses the credentials file,
including for renewal, and cannot be silenced except by addressing the issue
(e.g., by using a command like ``chmod 600`` to restrict access to the file).
Examples
--------
.. code-block:: bash
:caption: To acquire a certificate for ``example.com``
certbot certonly \\
--dns-corenetworks \\
--dns-corenetworks-credentials ~/.secrets/certbot/corenetworks.ini \\
-d example.com
.. code-block:: bash
:caption: To acquire a single certificate for both ``example.com`` and
``www.example.com``
certbot certonly \\
--dns-corenetworks \\
--dns-corenetworks-credentials ~/.secrets/certbot/corenetworks.ini \\
-d example.com \\
-d www.example.com
.. code-block:: bash
:caption: To acquire a certificate for ``example.com``, waiting 240 seconds
for DNS propagation
certbot certonly \\
--dns-corenetworks \\
--dns-corenetworks-credentials ~/.secrets/certbot/corenetworks.ini \\
--dns-corenetworks-propagation-seconds 240 \\
-d example.com
"""

View File

@@ -0,0 +1,84 @@
"""DNS Authenticator for Core Networks DNS."""
import logging
import zope.interface
from lexicon.providers import corenetworks
from certbot import errors
from certbot import interfaces
from certbot.plugins import dns_common
from certbot.plugins import dns_common_lexicon
logger = logging.getLogger(__name__)
ACCOUNT_URL = 'https://beta.api.core-networks.de/doc/#functon_auth_token'
@zope.interface.implementer(interfaces.IAuthenticator)
@zope.interface.provider(interfaces.IPluginFactory)
class Authenticator(dns_common.DNSAuthenticator):
"""DNS Authenticator for Core Networks
This Authenticator uses the Core Networks beta API to fulfill a dns-01 challenge.
"""
description = 'Obtain certificates using a DNS TXT record (if you are using Core Networks for DNS).'
ttl = 60
def __init__(self, *args, **kwargs):
super(Authenticator, self).__init__(*args, **kwargs)
self.credentials = None
@classmethod
def add_parser_arguments(cls, add): # pylint: disable=arguments-differ
super(Authenticator, cls).add_parser_arguments(add, default_propagation_seconds=30)
add('credentials', help='Core Networks credentials INI file.')
def more_info(self): # pylint: disable=missing-docstring,no-self-use
return 'This plugin configures a DNS TXT record to respond to a dns-01 challenge using ' + \
'the Core Networks beta API.'
def _setup_credentials(self):
self.credentials = self._configure_credentials(
'credentials',
'Core Networks credentials INI file',
{
'login': 'API user name for Core Networks beta API. (See {0}.)'.format(ACCOUNT_URL),
'password': 'Password for API user'
}
)
def _perform(self, domain, validation_name, validation):
self._get_corenetworks_client().add_txt_record(domain, validation_name, validation)
def _cleanup(self, domain, validation_name, validation):
self._get_corenetworks_client().del_txt_record(domain, validation_name, validation)
def _get_corenetworks_client(self):
return _CoreNetworksLexiconClient(self.credentials.conf('login'), self.credentials.conf('password'), self.ttl)
class _CoreNetworksLexiconClient(dns_common_lexicon.LexiconClient):
"""
Encapsulates all communication with the Core Networks API via Lexicon.
"""
def __init__(self, login, password, ttl):
super(_CoreNetworksLexiconClient, self).__init__()
config = dns_common_lexicon.build_lexicon_config('corenetworks', {
'ttl': ttl,
}, {
'auth_usernam': login,
'auth_password': password
})
self.provider = corenetworks.Provider(config)
def _handle_http_error(self, e, domain_name):
hint = None
if str(e).startswith('401 Client Error: Unauthorized for url:'):
hint = 'Is your API token value correct?'
return errors.PluginError('Error determining zone identifier for {0}: {1}.{2}'
.format(domain_name, e, ' ({0})'.format(hint) if hint else ''))

View File

@@ -0,0 +1,51 @@
"""Tests for certbot_dns_corenetworks.dns_corenetworks."""
import os
import unittest
import mock
from requests.exceptions import HTTPError
from certbot.plugins import dns_test_common
from certbot.plugins import dns_test_common_lexicon
from certbot.tests import util as test_util
LOGIN = 'foo'
PASSWORD = 'bar'
class AuthenticatorTest(test_util.TempDirTestCase,
dns_test_common_lexicon.BaseLexiconAuthenticatorTest):
def setUp(self):
super(AuthenticatorTest, self).setUp()
from certbot_dns_corenetworks.dns_corenetworks import Authenticator
path = os.path.join(self.tempdir, 'file.ini')
dns_test_common.write({"corenetworks_login": LOGIN, "corenetworks_password": PASSWORD }, path)
self.config = mock.MagicMock(corenetworks_credentials=path,
corenetworks_propagation_seconds=0) # don't wait during tests
self.auth = Authenticator(self.config, "corenetworks")
self.mock_client = mock.MagicMock()
# _get_corenetworks_client | pylint: disable=protected-access
self.auth._get_corenetworks_client = mock.MagicMock(return_value=self.mock_client)
class CoreNetworksLexiconClientTest(unittest.TestCase, dns_test_common_lexicon.BaseLexiconClientTest):
LOGIN_ERROR = HTTPError('401 Client Error: Unauthorized for url: ...')
def setUp(self):
from certbot_dns_corenetworks.dns_corenetworks import _CoreNetworksLexiconClient
self.client = _CoreNetworksLexiconClient(LOGIN, PASSWORD, 0)
self.provider_mock = mock.MagicMock()
self.client.provider = self.provider_mock
if __name__ == "__main__":
unittest.main() # pragma: no cover