libcloud-notifications mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From clewo...@apache.org
Subject [libcloud] 01/01: Enable auth to Cloudflare DNS via API Tokens
Date Sun, 07 Mar 2021 17:50:35 GMT
This is an automated email from the ASF dual-hosted git repository.

clewolff pushed a commit to branch dns-cloudflare-token-auth
in repository https://gitbox.apache.org/repos/asf/libcloud.git

commit 39508bff319e3964c6f7b063e63c89371413afe4
Author: Clemens Wolff <clewolff@microsoft.com>
AuthorDate: Sun Mar 7 12:46:50 2021 -0500

    Enable auth to Cloudflare DNS via API Tokens
---
 CHANGES.rst                                        |  6 ++++
 docs/dns/drivers/cloudflare.rst                    |  8 ++++-
 .../dns/cloudflare/instantiate_driver_token.py     |  5 +++
 libcloud/dns/drivers/cloudflare.py                 | 36 +++++++++++++++++++---
 libcloud/test/dns/test_cloudflare.py               | 10 ++++++
 5 files changed, 59 insertions(+), 6 deletions(-)

diff --git a/CHANGES.rst b/CHANGES.rst
index b0fab73..5455c60 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -41,6 +41,12 @@ Compute
   (GITHUB-1555)
   [Rob Juffermans - @robjuffermans]
 
+DNS
+~~~
+
+- [CloudFlare] Enable authentication via API Tokens.
+  [Clemens Wolff - @c-w]
+
 Changes in Apache Libcloud 3.3.1
 --------------------------------
 
diff --git a/docs/dns/drivers/cloudflare.rst b/docs/dns/drivers/cloudflare.rst
index b55951e..fb814d7 100644
--- a/docs/dns/drivers/cloudflare.rst
+++ b/docs/dns/drivers/cloudflare.rst
@@ -13,12 +13,18 @@ Instantiating the driver
 ------------------------
 
 To instantiate the driver you need to pass email address associated with your
-account and API key available on the `account page`_ to the driver constructor
+account and a Global API key available on the `account page`_ to the driver constructor
 as shown below.
 
 .. literalinclude:: /examples/dns/cloudflare/instantiate_driver.py
    :language: python
 
+Alternatively, authentication can also be done via an API Token as shown below.
+It is recommended that the token at least has the Zone.DNS permissions.
+
+.. literalinclude:: /examples/dns/cloudflare/instantiate_driver_token.py
+   :language: python
+
 API Docs
 --------
 
diff --git a/docs/examples/dns/cloudflare/instantiate_driver_token.py b/docs/examples/dns/cloudflare/instantiate_driver_token.py
new file mode 100644
index 0000000..ebda102
--- /dev/null
+++ b/docs/examples/dns/cloudflare/instantiate_driver_token.py
@@ -0,0 +1,5 @@
+from libcloud.dns.types import Provider
+from libcloud.dns.providers import get_driver
+
+cls = get_driver(Provider.CLOUDFLARE)
+driver = cls('<api token>')
diff --git a/libcloud/dns/drivers/cloudflare.py b/libcloud/dns/drivers/cloudflare.py
index 84bb5bd..0b91e28 100644
--- a/libcloud/dns/drivers/cloudflare.py
+++ b/libcloud/dns/drivers/cloudflare.py
@@ -20,7 +20,7 @@ __all__ = [
 import itertools
 import json
 
-from libcloud.common.base import JsonResponse, ConnectionUserAndKey
+from libcloud.common.base import JsonResponse, ConnectionKey, ConnectionUserAndKey
 from libcloud.common.types import InvalidCredsError, LibcloudError
 from libcloud.dns.base import DNSDriver, Zone, Record
 from libcloud.dns.types import Provider, RecordType
@@ -146,11 +146,16 @@ class CloudFlareDNSResponse(JsonResponse):
             raise exception_class(**kwargs)
 
 
-class CloudFlareDNSConnection(ConnectionUserAndKey):
+class BaseDNSConnection:
     host = API_HOST
     secure = True
     responseCls = CloudFlareDNSResponse
 
+    def encode_data(self, data):
+        return json.dumps(data)
+
+
+class GlobalAPIKeyDNSConnection(BaseDNSConnection, ConnectionUserAndKey):
     def add_default_headers(self, headers):
         headers['Content-Type'] = 'application/json'
         headers['X-Auth-Email'] = self.user_id
@@ -158,15 +163,20 @@ class CloudFlareDNSConnection(ConnectionUserAndKey):
 
         return headers
 
-    def encode_data(self, data):
-        return json.dumps(data)
+
+class TokenDNSConnection(BaseDNSConnection, ConnectionKey):
+    def add_default_headers(self, headers):
+        headers['Content-Type'] = 'application/json'
+        headers['Authorization'] = 'Bearer %s' % self.key
+
+        return headers
 
 
 class CloudFlareDNSDriver(DNSDriver):
     type = Provider.CLOUDFLARE
     name = 'CloudFlare DNS'
     website = 'https://www.cloudflare.com'
-    connectionCls = CloudFlareDNSConnection
+    connectionCls = GlobalAPIKeyDNSConnection
 
     RECORD_TYPE_MAP = {
         RecordType.A: 'A',
@@ -184,6 +194,22 @@ class CloudFlareDNSDriver(DNSDriver):
     RECORDS_PAGE_SIZE = 100
     MEMBERSHIPS_PAGE_SIZE = 50
 
+    def __init__(self,
+                 key,  # type: str
+                 secret=None,  # type: Optional[str]
+                 secure=True,  # type: bool
+                 host=None,  # type: Optional[str]
+                 port=None,  # type: Optional[int]
+                 **kwargs  # type: Optional[Any]
+                 ):
+
+        if secret is None:
+            self.connectionCls = TokenDNSConnection
+
+        super(CloudFlareDNSDriver, self).__init__(
+            key=key, secret=secret, secure=secure,
+            host=host, port=port, **kwargs)
+
     def iterate_zones(self):
         def _iterate_zones(params):
             url = '{}/zones'.format(API_BASE)
diff --git a/libcloud/test/dns/test_cloudflare.py b/libcloud/test/dns/test_cloudflare.py
index 125edf2..5f97c55 100644
--- a/libcloud/test/dns/test_cloudflare.py
+++ b/libcloud/test/dns/test_cloudflare.py
@@ -21,6 +21,8 @@ from libcloud.common.types import LibcloudError
 from libcloud.test import unittest
 
 from libcloud.dns.drivers.cloudflare import CloudFlareDNSDriver
+from libcloud.dns.drivers.cloudflare import GlobalAPIKeyDNSConnection
+from libcloud.dns.drivers.cloudflare import TokenDNSConnection
 from libcloud.dns.drivers.cloudflare import ZONE_EXTRA_ATTRIBUTES
 from libcloud.dns.drivers.cloudflare import RECORD_EXTRA_ATTRIBUTES
 from libcloud.dns.types import RecordType
@@ -42,6 +44,14 @@ class CloudFlareDNSDriverTestCase(unittest.TestCase):
         CloudFlareMockHttp.use_param = 'a'
         self.driver = CloudFlareDNSDriver(*DNS_PARAMS_CLOUDFLARE)
 
+    def test_auth_key(self):
+        driver = CloudFlareDNSDriver('user@example.com', 'key')
+        self.assertEqual(driver.connectionCls, GlobalAPIKeyDNSConnection)
+
+    def test_auth_token(self):
+        driver = CloudFlareDNSDriver('sometoken')
+        self.assertEqual(driver.connectionCls, TokenDNSConnection)
+
     def test_list_record_types(self):
         record_types = self.driver.list_record_types()
         self.assertEqual(len(record_types), 9)


Mime
View raw message