Skip to content

Commit

Permalink
auth methods cleaned up to allow empty/null strings in values plus co…
Browse files Browse the repository at this point in the history
…nfirmed all authentication code is consistent. Updated README.
  • Loading branch information
mahtin committed Jan 8, 2020
1 parent f71c3e2 commit ca5cb96
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 40 deletions.
84 changes: 51 additions & 33 deletions CloudFlare/cloudflare.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,33 +41,42 @@ def call_with_no_auth(self, method, parts,
params=None, data=None, files=None):
""" Cloudflare v4 API"""

headers = {
'User-Agent': self.user_agent,
'Content-Type': 'application/json'
}
headers = {}
self._add_headers(headers)
return self._call(method, headers, parts,
identifier1, identifier2, identifier3,
params, data, files)

def _add_headers(self, headers):
""" Add default headers """
headers['User-Agent'] = self.user_agent
headers['Content-Type'] = 'application/json'

def _add_auth_headers(self, headers):
""" Add authentication headers """
if self.email:
if self.email is None and self.token is None:
raise CloudFlareAPIError(0, 'no email and no token defined')
if self.token is None:
raise CloudFlareAPIError(0, 'no token defined')
if self.email is None:
headers['Authorization'] = 'Bearer %s' % (self.token)
else:
headers['X-Auth-Email'] = self.email
headers['X-Auth-Key'] = self.token
else:
headers['Authorization'] = 'Bearer {}'.format(self.token)

def _add_certtoken_headers(self, headers):
""" Add authentication headers """
if self.certtoken is None:
raise CloudFlareAPIError(0, 'no cert token defined')
headers['X-Auth-User-Service-Key'] = self.certtoken

def call_with_auth(self, method, parts,
identifier1=None, identifier2=None, identifier3=None,
params=None, data=None, files=None):
""" Cloudflare v4 API"""

if self.email is '' or self.token is '':
raise CloudFlareAPIError(0, 'no email and/or token defined')
headers = {
'User-Agent': self.user_agent,
'Content-Type': 'application/json'
}
headers = {}
self._add_headers(headers)
self._add_auth_headers(headers)
if type(data) == str:
# passing javascript vs JSON
Expand All @@ -86,12 +95,8 @@ def call_with_auth_unwrapped(self, method, parts,
params=None, data=None, files=None):
""" Cloudflare v4 API"""

if self.email is '' or self.token is '':
raise CloudFlareAPIError(0, 'no email and/or token defined')
headers = {
'User-Agent': self.user_agent,
'Content-Type': 'application/json'
}
headers = {}
self._add_headers(headers)
self._add_auth_headers(headers)
if type(data) == str:
# passing javascript vs JSON
Expand All @@ -110,13 +115,9 @@ def call_with_certauth(self, method, parts,
params=None, data=None, files=None):
""" Cloudflare v4 API"""

if self.certtoken is '' or self.certtoken is None:
raise CloudFlareAPIError(0, 'no cert token defined')
headers = {
'User-Agent': self.user_agent,
'X-Auth-User-Service-Key': self.certtoken,
'Content-Type': 'application/json'
}
headers = {}
self._add_headers(headers)
self._add_certtoken_headers(headers)
return self._call(method, headers, parts,
identifier1, identifier2, identifier3,
params, data, files)
Expand Down Expand Up @@ -245,7 +246,7 @@ def _network(self, method, headers, parts,
self.logger.debug('Call: done!')
except Exception as e:
if self.logger:
self.logger.debug('Call: exception!')
self.logger.debug('Call: exception! "%s"' % (e))
raise CloudFlareAPIError(0, 'connection failed.')

if self.logger:
Expand Down Expand Up @@ -835,6 +836,12 @@ def __init__(self, email=None, token=None, certtoken=None, debug=False, raw=Fals
if certtoken is None:
certtoken = conf_certtoken

if email is '':
email = None
if token is '':
token = None
if certtoken is '':
certtoken = None
self._base = self._v4base(email, token, certtoken, base_url, debug, raw, use_sessions)

# add the API calls
Expand All @@ -861,13 +868,24 @@ def __exit__(self, t, v, tb):
def __str__(self):
""" Cloudflare v4 API"""

return '["%s","%s"]' % (self._base.email, "REDACTED")
if self._base.email is None:
return '["%s"]' % ('REDACTED')
else:
return '["%s","%s"]' % (self._base.email, 'REDACTED')

def __repr__(self):
""" Cloudflare v4 API"""

return '%s,%s(%s,"%s","%s","%s",%s,"%s")' % (
self.__module__, type(self).__name__,
self._base.email, 'REDACTED', 'REDACTED',
self._base.base_url, self._base.raw, self._base.user_agent
)
if self._base.email is None:
return '%s,%s(%s,"%s","%s",%s,"%s")' % (
self.__module__, type(self).__name__,
'REDACTED', 'REDACTED',
self._base.base_url, self._base.raw, self._base.user_agent
)
else:
return '%s,%s(%s,"%s","%s","%s",%s,"%s")' % (
self.__module__, type(self).__name__,
self._base.email, 'REDACTED', 'REDACTED',
self._base.base_url, self._base.raw, self._base.user_agent
)

2 changes: 2 additions & 0 deletions CloudFlare/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,7 @@ def sanitize_secrets(secrets):
secrets_copy['X-Auth-Key'] = redacted_phrase
elif 'X-Auth-User-Service-Key' in secrets_copy:
secrets_copy['X-Auth-User-Service-Key'] = redacted_phrase
elif 'Authorization' in secrets_copy:
secrets_copy['Authorization'] = redacted_phrase

return secrets_copy
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ import CloudFlare

If the account email and API key are not passed when you create the class, then they are retrieved from either the users exported shell environment variables or the .cloudflare.cfg or ~/.cloudflare.cfg or ~/.cloudflare/cloudflare.cfg files, in that order.

If you're using an API Token, any `cloudflare.cfg` file must not contain an `email` attribute and the `CF_API_EMAIL` environment variable must be unset, otherwise the token will be treated as a key and will throw an error.
If you're using an API Token, any `cloudflare.cfg` file must either not contain an `email` attribute or be a zero length string and the `CF_API_EMAIL` environment variable must be unset or be a zero length string, otherwise the token will be treated as a key and will throw an error.

There is one call that presently doesn't need any email or token certification (the */ips* call); hence you can test without any values saved away.

Expand Down
13 changes: 7 additions & 6 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -225,10 +225,11 @@ class, then they are retrieved from either the users exported shell
environment variables or the .cloudflare.cfg or ~/.cloudflare.cfg or
~/.cloudflare/cloudflare.cfg files, in that order.

If you're using an API Token, any ``cloudflare.cfg`` file must not
contain an ``email`` attribute and the ``CF_API_EMAIL`` environment
variable must be unset, otherwise the token will be treated as a key
and will throw an error.
If you're using an API Token, any ``cloudflare.cfg`` file must either
not contain an ``email`` attribute or be a zero length string and the
``CF_API_EMAIL`` environment variable must be unset or be a zero length
string, otherwise the token will be treated as a key and will throw an
error.

There is one call that presently doesn't need any email or token
certification (the */ips* call); hence you can test without any values
Expand Down Expand Up @@ -362,8 +363,8 @@ The other raised response is **CloudFlareInternalError** which can
happen when calling an invalid method.

In some cases more than one error is returned. In this case the return
value **e** is also an array. You can iterate over that array to see
the additional error.
value **e** is also an array. You can iterate over that array to see the
additional error.

.. code:: python
Expand Down

0 comments on commit ca5cb96

Please sign in to comment.