Skip to content

Commit

Permalink
Give a flag to set explicitly the zone ID and avoid unscoped API toke…
Browse files Browse the repository at this point in the history
…ns (#501)
  • Loading branch information
adferrand authored May 5, 2020
1 parent 2b39b12 commit 010eeef
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 14 deletions.
41 changes: 28 additions & 13 deletions lexicon/providers/cloudflare.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,23 @@ def provider_parser(subparser):
"""Return the parser for this provider"""
subparser.description = '''
There are two ways to provide an authentication granting edition to the target CloudFlare DNS zone.
1 - A Global API key, with both --auth-username and --auth-token flags.
2 - An API token (permissions Zone:Zone(read) + Zone:DNS(edit) for all zones), with only --auth-token flag.
1 - A Global API key,
with --auth-username and --auth-token flags.
2 - An unscoped API token (permissions Zone:Zone(read) + Zone:DNS(edit) for all zones),
with --auth-token flag.
3 - A scoped API token (permissions Zone:Zone(read) + Zone:DNS(edit) for one zone),
with --auth-token and --zone-id flags.
'''
subparser.add_argument(
"--auth-username",
help="specify email address for authentication (for Global API key only)")
subparser.add_argument(
"--auth-token",
help="specify token for authentication (Global API key or API token)")
subparser.add_argument(
"--zone-id",
help="specify the zone id (if set, API token can be scoped to the target zone)"
)


class Provider(BaseProvider):
Expand All @@ -35,21 +43,28 @@ def __init__(self, config):
self.api_endpoint = 'https://api.cloudflare.com/client/v4'

def _authenticate(self):
zone_id = self._get_provider_option('zone_id')
if not zone_id:
payload = self._get('/zones', {
'name': self.domain,
'status': 'active'
})

if not payload['result']:
raise Exception('No domain found')
if len(payload['result']) > 1:
raise Exception('Too many domains found. This should not happen')

self.domain_id = payload['result'][0]['id']
else:
payload = self._get('/zones/{0}'.format(zone_id))

payload = self._get('/zones', {
'name': self.domain,
'status': 'active'
})

if not payload['result']:
raise Exception('No domain found')
if len(payload['result']) > 1:
raise Exception('Too many domains found. This should not happen')
if not payload['result']:
raise Exception('No domain found for Zone ID {0}'.format(zone_id))

self.domain_id = payload['result'][0]['id']
self.domain_id = zone_id

# Create record. If record already exists with the same content, do nothing'

def _create_record(self, rtype, name, content):
data = {'type': rtype, 'name': self._full_name(
name), 'content': content}
Expand Down
4 changes: 3 additions & 1 deletion lexicon/tests/providers/test_cloudflare.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,7 @@ def _filter_headers(self):
# We do not want to have "placeholder_auth_username" as default value for `--auth-username`
# if Bearer tokens are used to execute the tests, because the non-emptiness of this flags
# triggers interpretation of `--auth-key` as a Global API key.
# Similarly for `--zone-id`, we want to control when its value is not empty, because
# it will change the logic of the authentication process.
def _test_fallback_fn(self):
return lambda x: 'placeholder_' + x if x != 'auth_username' else ''
return lambda x: 'placeholder_' + x if x not in ('auth_username', 'zone_id') else ''

0 comments on commit 010eeef

Please sign in to comment.