duosecurity / duo_client_python

Python library for interacting with the Duo Auth, Admin, and Accounts APIs
https://duo.com/docs/
Other
137 stars 136 forks source link

metadata parse error in add_user_phone #219

Closed thehilll closed 1 year ago

thehilll commented 1 year ago

When trying to add an existing phone to an existing user, e.g. with:

import duo_client
admin_api = duo_client.Admin(
    ikey="xxx",
    skey="xxx",
    host="api-xxx.duosecurity.com"
)
admin_api.add_user_phone(user_id="userxxx", phone_id="phonexxx")

I am running into this error:

Traceback (most recent call last):
  File "/home/test/./duo_test.py", line 8, in <module>
    admin_api.add_user_phone(user_id="userxxx", phone_id="phonexxx")
  File "/home/applications-home/python/default_venv_3/lib/python3.9/site-packages/duo_client/admin.py", line 1010, in add_user_phone
    return self.json_api_call('POST', path, params)
  File "/home/applications-home/python/default_venv_3/lib/python3.9/site-packages/duo_client/client.py", line 479, in json_api_call
    return self.parse_json_response(response, data)
  File "/home/applications-home/python/default_venv_3/lib/python3.9/site-packages/duo_client/client.py", line 545, in parse_json_response
    (response, metadata) = self.parse_json_response_and_metadata(response, data)
  File "/home/applications-home/python/default_venv_3/lib/python3.9/site-packages/duo_client/client.py", line 589, in parse_json_response_and_metadata
    metadata = response.get('metadata', {})
AttributeError: 'str' object has no attribute 'get'

I believe the issue is that according to the API docs the response to this call should be:

{
  "stat": "OK",
  "response": ""
}

parse_json_response_and_metadata tries to parse this response with:

data = json.loads(data)
if data['stat'] != 'OK':
    raise_error('Received error response: %s' % data)
response = data['response']
metadata = data.get('metadata', {})
if not metadata and not isinstance(response, list):
    metadata = response.get('metadata', {})

Since there is no metadata key at the top level it tries to pull the metadata key from within response, but that is an empty string in this case, so the .get method fails.

I'm not sure what your preferred approach to fixing this would be, obviously this would work:

if not metadata and not isinstance(response, list) and response:
    metadata = response.get('metadata', {})
else:
    metadata = {}

But maybe that would cause other issues?

thehilll commented 1 year ago

And sorry, this is with duo-client 5.0.0.

AaronAtDuo commented 1 year ago

https://github.com/duosecurity/duo_client_python/pull/214 was meant to address this. Clearly that didn't quite do the job. Thanks for letting us know - we'll look into it.

yizshi commented 1 year ago

5.0.1 is out with fix for this issue :)

thehilll commented 1 year ago

Thank you. This fixed it for us.