Further adaptions
This commit is contained in:
85
certbot_dns_corenetworks/__init__.py
Normal file
85
certbot_dns_corenetworks/__init__.py
Normal 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
|
||||
|
||||
"""
|
||||
84
certbot_dns_corenetworks/dns_corenetworks.py
Normal file
84
certbot_dns_corenetworks/dns_corenetworks.py
Normal 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 ''))
|
||||
51
certbot_dns_corenetworks/dns_corenetworks_test.py
Normal file
51
certbot_dns_corenetworks/dns_corenetworks_test.py
Normal 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
|
||||
Reference in New Issue
Block a user