Giter Club home page Giter Club logo

duo_client_python's People

Contributors

aaronatduo avatar asealey avatar axorna avatar ben-duo avatar cavemanpi avatar ccassell avatar claycooper avatar erikbarbara avatar gkelly avatar gurleenatduo avatar jackwink avatar jaherne avatar jaherne-duo avatar jcheng-duo avatar jeffreyparker avatar jpringle03 avatar juangw avatar ldllano avatar marktripod-duo avatar mbish avatar midnightlynx avatar mschwager avatar nomadmtb avatar nstojcevich avatar robsmall avatar vbscott avatar xdesai avatar yizshi avatar zcoughl avatar zweglarz avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

duo_client_python's Issues

sig v4 implementation does not work

For example (on macOS, but it fails regardless of the platform):

client = duo_client.client.Client(
	ikey=IKEY,
	skey=SKEY,
	host=HOST,
	digestmod=hashlib.sha512,
	sig_version=4,
)

data = client.json_api_call('GET', '/path/to/resource', {})

Raises:

Traceback (most recent call last):
  File "/usr/local/Cellar/[email protected]/3.9.10/Frameworks/Python.framework/Versions/3.9/lib/python3.9/urllib/parse.py", line 938, in urlencode
    raise TypeError
TypeError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "test.py", line 18, in <module>
    data = client.json_api_call('GET', '/path/to/resource', {})
  File "/usr/local/lib/python3.9/site-packages/duo_client/client.py", line 388, in json_api_call
    (response, data) = self.api_call(method, path, params)
  File "/usr/local/lib/python3.9/site-packages/duo_client/client.py", line 265, in api_call
    uri = path + '?' + six.moves.urllib.parse.urlencode(params, doseq=True)
  File "/usr/local/Cellar/[email protected]/3.9.10/Frameworks/Python.framework/Versions/3.9/lib/python3.9/urllib/parse.py", line 945, in urlencode
    raise TypeError("not a valid non-string sequence "
  File "/usr/local/Cellar/[email protected]/3.9.10/Frameworks/Python.framework/Versions/3.9/lib/python3.9/urllib/parse.py", line 938, in urlencode
    raise TypeError
TypeError: not a valid non-string sequence or mapping object 

Authenticated Proxies Support

Hi there,

I'm working on a integration with the Duo Admin API client and this client works great locally. However for communicating with Duo from our datacenters, it is required to use an authenticated proxy. I am wondering if you could confirm if this client can support authenticated proxies?

I receive the following error when I specific proxy host to be in the format of;
proxy_user:[email protected]

duo_client-3.0-py2.py3-none-any.whl/duo_client/https_wrapper.py", line 113, in connect
    self.timeout)
  File "/opt/ee/python/2.7/lib/python2.7/socket.py", line 557, in create_connection
    for res in getaddrinfo(host, port, 0, SOCK_STREAM):
socket.gaierror: [Errno -2] Name or service not known

If I leave the proxy in the simple format with no authentication, I get denied auth from the egress proxy:
http.proxyhost.com

duo_client-3.0-py2.py3-none-any.whl/duo_client/client.py", line 262, in _make_request
    conn.request(method, uri, body, headers)
  File "/opt/ee/python/2.7/lib/python2.7/httplib.py", line 1042, in request
    self._send_request(method, url, body, headers)
  File "/opt/ee/python/2.7/lib/python2.7/httplib.py", line 1082, in _send_request
    self.endheaders(body)
  File "/opt/ee/python/2.7/lib/python2.7/httplib.py", line 1038, in endheaders
    self._send_output(message_body)
  File "/opt/ee/python/2.7/lib/python2.7/httplib.py", line 882, in _send_output
    self.send(msg)
  File "/opt/ee/python/2.7/lib/python2.7/httplib.py", line 844, in send
    self.connect()
  File "/opt/ee/python/2.7/lib/python2.7/httplib.py", line 824, in connect
    self._tunnel()
  File "/opt/ee/python/2.7/lib/python2.7/httplib.py", line 806, in _tunnel
    message.strip()))
socket.error: Tunnel connection failed: 407 Proxy Authentication Required

I was hoping it might be possible to pass the authentication through in some form of:

  • duo_client.Admin().set_proxy(headers="proxy_auth)

Thanks!
Mat

get_billing_and_telephony_credits.py ("RuntimeError: Received 403 Access forbidden")

Currently set to Role "Owner" however when I do run the "get_billing_and_telephony_credits.py" I get this error =>

Traceback (most recent call last):
File "c:\Users\46707\python_testingNmore\duo_client_python\examples\get_billing_and_telephony_credits.py", line 35, in
child_accounts = accounts_api.get_child_accounts()
File "c:\Users\46707\python_testingNmore\duo_client_python\venv\lib\site-packages\duo_client-4.3.2-py3.9.egg\duo_client\accounts.py", line 15, in get_child_accounts
response = self.json_api_call('POST',
File "c:\Users\46707\python_testingNmore\duo_client_python\venv\lib\site-packages\duo_client-4.3.2-py3.9.egg\duo_client\client.py", line 390, in json_api_call
return self.parse_json_response(response, data)
File "c:\Users\46707\python_testingNmore\duo_client_python\venv\lib\site-packages\duo_client-4.3.2-py3.9.egg\duo_client\client.py", line 456, in parse_json_response
(response, metadata) = self.parse_json_response_and_metadata(response, data)
File "c:\Users\46707\python_testingNmore\duo_client_python\venv\lib\site-packages\duo_client-4.3.2-py3.9.egg\duo_client\client.py", line 483, in parse_json_response_and_metadata
raise_error('Received %s %s' % (
File "c:\Users\46707\python_testingNmore\duo_client_python\venv\lib\site-packages\duo_client-4.3.2-py3.9.egg\duo_client\client.py", line 469, in raise_error
raise error
RuntimeError: Received 403 Access forbidden

I have made sure to set my IP as the only one to be able to access the Admin Api. As the owner I have also set all the permissions in the Admin Api duo portal to true.

unable to login: 401 Invalid Intergration key in request credentials

hi guys,

I've tried to get this working but I'm unable to do so. could you please help me?
offcourse I double checked the login!

Traceback (most recent call last):
File "duotest.py", line 25, in
users = admin_api.get_users()
File "/home/admin/.local/lib/python3.6/site-packages/duo_client/admin.py", line 527, in get_users
return list(self.get_users_iterator())
File "/home/admin/.local/lib/python3.6/site-packages/duo_client/client.py", line 400, in json_paging_api_call
(objects, metadata) = self.parse_json_response_and_metadata(response, data)
File "/home/admin/.local/lib/python3.6/site-packages/duo_client/client.py", line 438, in parse_json_response_and_metadata
data['message'],
File "/home/admin/.local/lib/python3.6/site-packages/duo_client/client.py", line 422, in raise_error
raise error
RuntimeError: Received 401 Invalid integration key in request credentials

Could not find a version that satisfies the requirement duo_client

C:\Users\mschloss\Python\duo_client_python-master>C:\Python27\Scripts\pip.exe install duo_client
Collecting duo_client
Could not find a version that satisfies the requirement duo_client (from versions: )
No matching distribution found for duo_client

Windows 10
Python 2.7
Pip or Pip2 9.0.3

SSL error

I'm trying to use this in Amazon Linux 2, with python 3.7.9 and the latest duo_client. I get:

  File "/usr/local/lib/python3.8/site-packages/duo_client/admin.py", line 528, in get_users
    return list(self.get_users_iterator())
  File "/usr/local/lib/python3.8/site-packages/duo_client/client.py", line 406, in json_paging_api_call
    (response, data) = self.api_call(method, path, params)
  File "/usr/local/lib/python3.8/site-packages/duo_client/admin.py", line 196, in api_call
    return super(Admin, self).api_call(method, path, params)
  File "/usr/local/lib/python3.8/site-packages/duo_client/client.py", line 276, in api_call
    return self._make_request(method, uri, body, encoded_headers)
  File "/usr/local/lib/python3.8/site-packages/duo_client/client.py", line 344, in _make_request
    response, data = self._attempt_single_request(
  File "/usr/local/lib/python3.8/site-packages/duo_client/client.py", line 357, in _attempt_single_request
    conn.request(method, uri, body, headers)
  File "/usr/lib64/python3.8/http/client.py", line 1255, in request
    self._send_request(method, url, body, headers, encode_chunked)
  File "/usr/lib64/python3.8/http/client.py", line 1301, in _send_request
    self.endheaders(body, encode_chunked=encode_chunked)
  File "/usr/lib64/python3.8/http/client.py", line 1250, in endheaders
    self._send_output(message_body, encode_chunked=encode_chunked)
  File "/usr/lib64/python3.8/http/client.py", line 1010, in _send_output
    self.send(msg)
  File "/usr/lib64/python3.8/http/client.py", line 950, in send
    self.connect()
  File "/usr/local/lib/python3.8/site-packages/duo_client/https_wrapper.py", line 121, in connect
    self.sock = self.default_ssl_context.wrap_socket(self.sock)
  File "/usr/lib64/python3.8/ssl.py", line 500, in wrap_socket
    return self.sslsocket_class._create(
  File "/usr/lib64/python3.8/ssl.py", line 1040, in _create
    self.do_handshake()
  File "/usr/lib64/python3.8/ssl.py", line 1309, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLEOFError: EOF occurred in violation of protocol (_ssl.c:1123)

Any suggestions? Python requests doesn't have any ssl issues, so I don't see why this would.

Client sends two `Host` headers

It appears that the Client erroneously sends two Host headers during requests:

GET /auth/v2/ping? HTTP/1.1\r
Host: localhost\r
Accept-Encoding: identity\r
Authorization: Basic aWtleTphMTNiMDcwYzI4MmU3NDY0NDEwYWZkYjdmZGQ2YWY0MDc3OGM1Zjcw\r
Date: Wed, 19 May 2021 01:46:41 -0000\r
Host: localhost\r
User-Agent: Duo API Python/4.3.1\r
\r

Deprecation warning due to invalid escape sequences

Deprecation warnings are raised due to invalid escape sequences. This can be fixed by using raw strings or escaping the literals. pyupgrade also helps in automatic conversion : https://github.com/asottile/pyupgrade/

find . -iname '*.py' | grep -Ev 'vendor|example|doc|tools|sphinx' | xargs -P4 -I{} python3.8 -Wall -m py_compile {}
./duo_client/https_wrapper.py:110: DeprecationWarning: invalid escape sequence \.
  host_re = host.replace('.', '\.').replace('*', '[^.]*')

auth_logs request uses 'GET' but doesn't check for URI limits

get_authentication_log takes a parameter of a list of user_ids. This list can be arbitrarily long in code, but this endpoint in duo_client_python passes the encoded parameters as a GET request, which has a max length per the HTTP RFC (and as a result needs to be split to complete). Documentation indicates that v2 of the log endpoint supports GET OR POST (https://duo.com/docs/adminapi#authentication-logs) , this does NOT appear to be correct. As POST requests fail with a 405. As a result, the length of the parameters needs to be analyzed prior to sending the request.

(Pdb) out_uri
'https://api-[REMOVED].duosecurity.com/admin/v2/logs/authentication'
(Pdb) data
{'mintime': '1639679487000', 'maxtime': '1639765887000', 'sort': 'ts:asc', 'limit': '100', 'offset': '0'}
(Pdb) headers
{b'Authorization': b'Basic ]REMOVED]==', b'Date': b'Fri, 17 Dec 2021 18:31:27 -0000', b'User-Agent': b'Duo API Python/4.3.2', b'Content-type': b'application/x-www-form-urlencoded'}
(Pdb) method
'POST'
(Pdb) resp = requests.post(out_uri, data=data, headers=headers)
(Pdb) print(f"status_code = {resp.status_code}")
status_code = 405

response = self.json_api_call(

bdist_rpm does not build an RPM

Running python setup.py bdist_rpm bombs out:

+ python setup.py build
Traceback (most recent call last):
  File "setup.py", line 17, in <module>
    with open(requirements_dev_filename) as fd:
IOError: [Errno 2] No such file or directory: '/home/me/VPN/duo_client_python/build/bdist.linux-x86_64/rpm/BUILD/duo_client-3.1.0/requirements-dev.txt'
error: Bad exit status from /var/tmp/rpm-tmp.ZZiQil (%build)

I think the simple fix is to add requirements-dev.txt to MANIFEST.in, but perhaps there's a different way that fits with why there's a dev file to begin with.

get_authentication_log pagination confusion

Hi,
I'm having trouble using the SDK to paginate responses as I'd expect and I've dug through the documentation and source and unfortunately it isn't clear to me.

The api documentation https://duo.com/docs/adminapi#logs appears to refer to next_offset as a single number which will offset the results by that number, sort of like a skip that many results and then get the rest. However in my REST request the response gives me {'next_offset': ['1553043904936', 'e32e02c3-a0d6-40bf-b6db-a109edf6d0ea'], 'total_objects': 1231} and that 1553043904936 is an epoch time of the current day.

The api documentation also says

"The offset at which to start record retrieval. This value is provided in the metadata in the form of a date string in milliseconds and the event txid. Both of these values must be provided when used (e.g. next_offset=1547486297000&next_offset=5bea1c1e-612c-4f1d-b310-75fd31385b15)"

but I'm confused as to how to enter that in using the SDK because the source code for the library doesn't appear to reference these fields in the method's description, it only lists the offset. And because i'm using the SDK the actual URL enpoint is kind of abstracted away from me so it's not clear how to add multiple "next_offset=" values in the URL

    "API Version v2:

    mintime (required) - Unix timestamp in ms; fetch records >= mintime
    maxtime (required) - Unix timestamp in ms; fetch records <= mintime
    limit - Number of results to limit to
    next_offset - Used to grab the next set of results from a previous response
    sort - Sort order to be applied
    users - List of user ids to filter on
    groups - List of group ids to filter on
    applications - List of application ids to filter on
    results - List of results to filter to filter on
    reasons - List of reasons to filter to filter on
    factors - List of factors to filter on
    event_types - List of event_types to filter on"

What would be the correct way to get all authentication logs when the total # is 1231?

Invalid Integration Key

I have application created and it has integration key and security key. However it shows Invalid Integration key.

Traceback (most recent call last):
File "examples/report_auths_by_country.py", line 25, in
logs = admin_api.get_authentication_log()
File "/home/ubuntu/.local/lib/python3.8/site-packages/duo_client/admin.py", line 452, in get_authentication_log
response = self.json_api_call(
File "/home/ubuntu/.local/lib/python3.8/site-packages/duo_client/client.py", line 383, in json_api_call
return self.parse_json_response(response, data)
File "/home/ubuntu/.local/lib/python3.8/site-packages/duo_client/client.py", line 409, in parse_json_response
(response, metadata) = self.parse_json_response_and_metadata(response, data)
File "/home/ubuntu/.local/lib/python3.8/site-packages/duo_client/client.py", line 436, in parse_json_response_and_metadata
raise_error('Received %s %s' % (
File "/home/ubuntu/.local/lib/python3.8/site-packages/duo_client/client.py", line 422, in raise_error
raise error
RuntimeError: Received 401 Invalid integration key in request credentials

No wheel distributions for Python 3.

Hey All,
Your TravisCI config looks like you test against Python 3.3/3.4 but you aren't publishing and Python3 wheels to PyPI. This makes you have to monkey with the wheel filename to install on Python 3 and gives the sense that what you are doing isn't supported.

Maybe your library is only Python2... but since you are testing on 3, I'm hoping maybe you just need to change your distribution settings a tiny bit.

https://pypi.python.org/pypi/duo_client/3.0

Cheers.

Increase _MAX_BACKOFF_WAIT_SECS seconds

next_offset=['[offset1]', '[offset2]']
429
Sleeping for 1.6818238383872655
429
Sleeping for 2.8658061545293907
429
Sleeping for 4.266326646211362
429
Sleeping for 8.58080225730511
429
Sleeping for 16.02056706813436
429
Sleeping for 32.86096999735611
429
Traceback (most recent call last):
  File "/test.py", line 13, in <module>
    res = admin_api.get_authentication_log()
  File "/duo_client/admin.py", line 479, in get_authentication_log
    return list(self.get_authentication_log_iterator(api_version, params))
  File "/duo_client/client.py", line 415, in json_paging_api_call
    (objects, metadata) = self.parse_json_response_and_metadata(response, data)
  File "/duo_client_python/duo_client/client.py", line 491, in parse_json_response_and_metadata
    raise_error('Received %s %s' % (
  File "/duo_client_python/duo_client/client.py", line 477, in raise_error
    raise error
RuntimeError: Received 429 Too Many Requests

As has been demonstrated, It is possible to exceed this timeframe, which doesn't seem to be documented. Adding an additional iteration (aka 64, as opposed to 32) seemed to resolve most but not all observed issues.

ext_offset=['x', 'y']
429
Sleeping for 1.1092953488995574
429
Sleeping for 2.8283432090944345
429
Sleeping for 4.848998406819535
429
Sleeping for 8.35095954541268
429
Sleeping for 16.688679086577334
429
Sleeping for 32.90772754486507
429
Sleeping for 64.0423301176081
429
Traceback (most recent call last):
  File "test.py", line 13, in <module>
    res = admin_api.get_authentication_log()
  File "/duo_client/admin.py", line 479, in get_authentication_log
    return list(self.get_authentication_log_iterator(api_version, params))
  File "/duo_client/client.py", line 415, in json_paging_api_call
    next_offset = metadata.get('next_offset', None)
  File "/duo_client/client.py", line 491, in parse_json_response_and_metadata
    response.status,
  File "/duo_client/client.py", line 477, in raise_error
    if not isinstance(data, six.text_type):
RuntimeError: Received 429 Too Many Requests

The ideal situation is not to have a max iterator if this is not supported within the documentation, and allow for infinite attempts given that stopping in the middle of an iterator may break requests that take a long time to complete (like for auth_logs).

For code reference see

wait_secs > self._MAX_BACKOFF_WAIT_SECS):

New release with sync_user

#81 added a sync_user() method to the Admin object. It would be nice if this were released in a new version of the package.

client.py does not handle exceptions from httplib

CentOS7 box with python2.7 (I KNOW, I'm working on it RIGHT NOW).

On VERY rare occasions, my code gets an exception passed up through your library:

  File "/usr/lib/python2.7/site-packages/duo_client/auth.py", line 29, in check
    return self.json_api_call('GET', '/auth/v2/check', {})
  File "/usr/lib/python2.7/site-packages/duo_client/client.py", line 382, in json_api_call
    (response, data) = self.api_call(method, path, params)
  File "/usr/lib/python2.7/site-packages/duo_client/client.py", line 269, in api_call
    return self._make_request(method, uri, body, encoded_headers)
  File "/usr/lib/python2.7/site-packages/duo_client/client.py", line 338, in _make_request
    conn, method, uri, body, headers)
  File "/usr/lib/python2.7/site-packages/duo_client/client.py", line 351, in _attempt_single_request
    response = conn.getresponse()
  File "/usr/lib64/python2.7/httplib.py", line 1128, in getresponse
    response.begin()
  File "/usr/lib64/python2.7/httplib.py", line 453, in begin
    version, status, reason = self._read_status()
  File "/usr/lib64/python2.7/httplib.py", line 417, in _read_status
    raise BadStatusLine(line)
BadStatusLine: ''

I'd say, in 6 months, I've gotten about 4 of these (out of thousands of positive responses). I imagine it's a web burp in production.

This is mostly a question of "is this YOUR problem or MINE?" I see there's very few uses of try in the library, and none around conn.getresponse(), so I'm unsure if you consider it a design feature that your library is propagating httplib exceptions up to users' code, or if I've hit a super rare edge that you would handle, but nobody ran across in development.

Thanks!

get_authentication_log mintime argument returns an error on valid timestamps

So this isn't totally library-related, but the get_authentication_log mintime argument will cause a RuntimeError if any value is used outside of None.

Samples to reproduce:

import duo_client


admin_api = duo_client.Admin(
            ikey="xxxxxx",
            skey="xxxxxx",
            host="xxxxxxx"
        ).get_authentication_log(2, mintime="1555453710")
import duo_client


admin_api = duo_client.Admin(
            ikey="xxxxxx",
            skey="xxxxxx",
            host="xxxxxxx"
        ).get_authentication_log(2, mintime=1555453710)
import duo_client


admin_api = duo_client.Admin(
            ikey="xxxxxx",
            skey="xxxxxx",
            host="xxxxxxx"
        ).get_authentication_log(2, mintime=0)

The only way I have been able to successfully use this API endpoint is to totally omit the mintime value.

Upload to the Python Packaging Index

It would be incredibly convenient if you would upload this library to the Python Package Index.

In case you're not familiar with PyPI, all you have to do is register for an account at https://pypi.python.org/pypi, then check out duo_client_python and run

python setup.py sdist register upload

This will ask for your PyPI username and password and remember them in ~/.pypirc, so that future uploads don't need to ask for it again.

Advantages of having your package published in PyPI are:

  • people can find it
  • people can install it by running pip install duo_client
  • people who write libraries or applications can include it in their dependency lists by name

Getting all users using get_users

Good Morning,

I am having an issue using the get_users command. In DUO's Admin API, it states that only 300 users can be pulled at a time, and that I would have to specify an offset to get the next 300 users. So far, using the get_users command, I am able to pull up to at least 500 users with no issue. However, if this is an error on DUO's end and they end up correcting the error my script will no longer function. Would you be able to tell me the proper syntax of grabbing all the user's in groups of 300 at a time, using the offset?

Thank you,
Dustin

Querying Authlog with a maxtime of > now-2 minutes may lead to inconsistent behavior

Documentation says

There is an intentional two minute delay in availability of new authentications in the API response. Duo operates a large scale distributed system, and this two minute buffer period ensures that calls will return consistent results. Querying for results more recent than two minutes will return as empty.

However, maxtime is set by default to now. (see

params['maxtime'] = int(time.time()) * 1000
). Given this, it is quite possible that depending on refresh intervals the user will receive an empty list, when in fact results would be expected.

PR will appear as follows:

        # Querying for results more recent than two minutes will return as empty.
        if 'maxtime' not in params:
            params['maxtime'] = int(time.time() - 120) * 1000

"Invalid Integration key in request credentials"

I am having difficulty just getting the examples to run.

I've had DUO enable the Admin API on our plan. However, copying and pasting the integration key, secret key, and API hostname directly into the examples I am met with:

"RuntimeError: Received 401 Invalid integration key in request credentials"

Any additional steps that I am missing?

Thanks

admin-logs is failing randomly

I'm using this lambda_handler.py' with the latest duo-client` package on kubernetess and now I'm seeing the handler is failing randomly because of this error:

dumping logs
dumped successfully.
Retrieved admin Logs.
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/opt/sumologic-duo-security/lambda_function.py", line 102, in lambda_handler
    logs_admin = format_admin_logs(logs_admin)
  File "/opt/sumologic-duo-security/lambda_function.py", line 65, in format_admin_logs
    for ph in (i['description']['phones']):
TypeError: 'NoneType' object is not iterable

The handler could not fetch admin_logs

because this issue is happening randomly I guess there is a bug in the code
thanks

Unable to use on Google App Engine because of six' http_client

six.moves.http_client seems to handle the Host header manually.

Google App Engine doesn't like the Host header being set manually: https://cloud.google.com/appengine/docs/python/outbound-requests

For security reasons, the following headers cannot be modified by the application:

Content-Length
Host
Vary
Via
X-Appengine-Inbound-Appid
X-Forwarded-For
X-ProxyUser-IP

The end result is that you get an error in your log and all your requests 404:

WARNING 2016-12-27 16:54:18,604 urlfetch_stub.py:550] Stripped prohibited headers from URLFetch request: ['Host']

I don't have a recommendation for a fix right now (I am using my own implementation as a workaround), but wanted to make sure this issue was captured as the Python API client seems broken on GAE.

Admin API missing user email

Looks like the Admin API for Users should allow for email addresses to be set on a per user basis according to the API docs, but the python API appears to be missing that functionality.

group pagination not part of the code

Hi,

In duo_client/admin.py, there are get_user_groups and get_user_groups_iterator which (via json_paging_api_call in duo_client/client.py) seem to be doing the pagination for us (kinda already touched on in #63).

Minor note: per https://duo.com/docs/adminapi#retrieve-groups-by-user-id, get_user_groups should have limits of 100/500, but the API shows None. I don't particularly care here - you're doing the paging for me, so, "cool!"

What I'm opening an issue over is, get_group_users looks the same as get_user_groups from the docs https://duo.com/docs/adminapi#v2-groups-get-users. ("Same" as in, both API calls take optional paging-related parameters, with limits of 100/500 defined; obviously they return different data.) But there's no similar iterator/listmaker offered for get_group_users - you get back one limit-sized slurp of data. I'm not seeing the metadata get to me from a call to get_group_users in order to manage my own pagination, but that could be an error on my part.

If it's an oversight that get_group_users doesn't page, well, here's a request. If it's deliberate, is there something you can maybe drop in a comment for why this call is seemingly unique/different?

Thanks!

self register Landline callback

I have created a DUO self service registration site for a large client Chicago university. They are supporting all factors.. Event landline - Whats steps do you take to to activate a landline phone with
type: 'landline'
capabilities: 'phone'

Can we get an example? thx!

No module named 'duo_client'

Traceback (most recent call last):
File "report_users_and_phones.py", line 7, in
import duo_client
ModuleNotFoundError: No module named 'duo_client'

Retrieve Endpoint by ID

Would be great if there was a function in the admin client that covered this endpoint.

/admin/v1/endpoints/[epkey]

Getting access to "voice_enabled" attribute

I need to get a list of all users who have DUO set send them a Phone Call. I see that there's a modify_group() method where "voice_enabled" is a boolean that can be called; but that's just to change the method to Phone Call, correct? How can I get a list of users where that attribute is True? When I download all users' JSON I don't see that attribute available. Even if I call a user by name, the optional attribute of "voice_enabled" is not available. What am I missing?

Deprecated SSL protocol in CertValidatingHTTPSConnection

tl;dr: Line 72 of duo_client/https_wrapper.py hard-codes a deprecated (since Python 3.6) SSL protocol.

The only similar issue I found in this queue is #31, but it's pretty historic (2016) and only slightly related.


We've just upgraded Python (to 3.10.5) and found that at least one of our scripts using duo_client_python is emitting a new-to-us deprecation warning:

/path/to/python3.10/site-packages/duo_client/https_wrapper.py:72: DeprecationWarning: ssl.PROTOCOL_TLS is deprecated
  context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)

Line 72, referenced in the warning above is

context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)

ssl.PROTOCOL_SSLv23 is deprecated since Python 3.6 (docs.python.org). The replacement, ssl.PROTOCOL_TLS, which was introduced in Python 3.6 is itself deprecated, now, under Python 3.10:

Deprecated since version 3.10: TLS clients and servers require different default settings for secure communication. The generic TLS protocol constant is deprecated in favor of PROTOCOL_TLS_CLIENT and PROTOCOL_TLS_SERVER.

(docs.python.org)

ssl.PROTOCOL_TLS_CLIENT:

Auto-negotiate the highest protocol version that both the client and server support, and configure the context client-side connections. The protocol enables CERT_REQUIRED and check_hostname by default.

(docs.python.org)

No support for `alias1..4` parameter to `update_user`

Official API documentation states that update_user can accept a alias1..4 parameters. Attempting to feed this to update_user(), however, results in a TypeError.

TypeError: update_user() got an unexpected keyword argument 'alias1'

RPM packages don't list their distribution

When building an RPM for multiple platforms, you end up with a duo_client-3.1.0-1.noarch.rpm no matter whether the build was for CentOS7 or something else, which makes identifying the package from its name troublesome in package management. Even with noarch, the package contents are different between distro flavors.

Adding release = 1%{?dist} under the bdist_rpm section of setup.cfg would fix that.

'async' is a reserved keyword in Python 3.7

Basically, async is now a reserved keyword in Python 3.7, similar to return or def in earlier versions. The duo_client library makes use of async as a keyword argument in a few locations, namely duo_client/auth.py and duo_client/auth_v1.py, which causes a SyntaxError on Python 3.7:

ImportError: Failed to import test module: tests.test_client
Traceback (most recent call last):
  File "/home/travis/virtualenv/python3.7-dev/lib/python3.7/site-packages/nose2/plugins/loader/discovery.py", line 201, in _find_tests_in_file
    module = util.module_from_name(module_name)
  File "/home/travis/virtualenv/python3.7-dev/lib/python3.7/site-packages/nose2/util.py", line 77, in module_from_name
    __import__(name)
  File "/home/travis/build/duosecurity/duo_client_python/tests/test_client.py", line 4, in <module>
    import duo_client.client
  File "/home/travis/build/duosecurity/duo_client_python/duo_client/__init__.py", line 4, in <module>
    from .auth import Auth
  File "/home/travis/build/duosecurity/duo_client_python/duo_client/auth.py", line 115
    async=False,
        ^
SyntaxError: invalid syntax

TravisCI is catching this as well: https://travis-ci.org/duosecurity/duo_client_python/jobs/336651090

Python 3.7 is expected to come out sometime in the middle of 2018 (https://www.python.org/dev/peps/pep-0537/#schedule), we should probably fix this error before then. It's worth noting that this change will most likely require breaking changes, and for consumers to update their code to use the new keyword argument.

PEP 8 recommends appending a _ to make the keyword argument async_: https://www.python.org/dev/peps/pep-0008/#function-and-method-arguments

pip install now fails with error about six module

In a fresh virtualenv (python 2.7.5 on Linux), this works:

pip install git+https://github.com/duosecurity/duo_client_python@369fe43b8b09bf5948d88eaf0e1e1c78b584044a

while this doesn't:

pip install git+https://github.com/duosecurity/duo_client_python

Here's the pip.log:

------------------------------------------------------------
/tmp/pyenv/bin/pip run on Tue Sep  1 13:46:51 2015
Downloading/unpacking git+https://github.com/duosecurity/duo_client_python@d33f0f7d6f53b40939dd8edc908832922681fa82

  Cloning https://github.com/duosecurity/duo_client_python (to d33f0f7d6f53b40939dd8edc908832922681fa82) to ./pip-Mq6Yiv-build

  Found command 'git' at '/usr/bin/git'
  Running command /usr/bin/git clone -q https://github.com/duosecurity/duo_client_python /tmp/pip-Mq6Yiv-build
  Running command /usr/bin/git show-ref
  d37822ed4740e1fd9dd52bd58a3c7abaee91dbb1 refs/heads/master
  d37822ed4740e1fd9dd52bd58a3c7abaee91dbb1 refs/remotes/origin/HEAD
  d37822ed4740e1fd9dd52bd58a3c7abaee91dbb1 refs/remotes/origin/master
  Could not find a tag or branch 'd33f0f7d6f53b40939dd8edc908832922681fa82', assuming commit.

  Running command /usr/bin/git rev-parse HEAD
  d37822ed4740e1fd9dd52bd58a3c7abaee91dbb1
  Running command /usr/bin/git checkout -q d33f0f7d6f53b40939dd8edc908832922681fa82
  Running setup.py egg_info for package from git+https://github.com/duosecurity/duo_client_python@d33f0f7d6f53b40939dd8edc908832922681fa82

    Traceback (most recent call last):

      File "<string>", line 16, in <module>

      File "/tmp/pip-Mq6Yiv-build/setup.py", line 4, in <module>

        from duo_client import __version__

      File "duo_client/__init__.py", line 2, in <module>

        from .accounts import Accounts

      File "duo_client/accounts.py", line 7, in <module>

        from . import client

      File "duo_client/client.py", line 6, in <module>

        import six

    ImportError: No module named six

    Complete output from command python setup.py egg_info:

    Traceback (most recent call last):

  File "<string>", line 16, in <module>

  File "/tmp/pip-Mq6Yiv-build/setup.py", line 4, in <module>

    from duo_client import __version__

  File "duo_client/__init__.py", line 2, in <module>

    from .accounts import Accounts

  File "duo_client/accounts.py", line 7, in <module>

    from . import client

  File "duo_client/client.py", line 6, in <module>

    import six

ImportError: No module named six

----------------------------------------

Cleaning up...

Command python setup.py egg_info failed with error code 1 in /tmp/pip-Mq6Yiv-build

Exception information:
Traceback (most recent call last):
  File "/tmp/pyenv/lib/python2.7/site-packages/pip/basecommand.py", line 134, in main
    status = self.run(options, args)
  File "/tmp/pyenv/lib/python2.7/site-packages/pip/commands/install.py", line 236, in run
    requirement_set.prepare_files(finder, force_root_egg_info=self.bundle, bundle=self.bundle)
  File "/tmp/pyenv/lib/python2.7/site-packages/pip/req.py", line 1134, in prepare_files
    req_to_install.run_egg_info()
  File "/tmp/pyenv/lib/python2.7/site-packages/pip/req.py", line 259, in run_egg_info
    command_desc='python setup.py egg_info')
  File "/tmp/pyenv/lib/python2.7/site-packages/pip/util.py", line 670, in call_subprocess
    % (command_desc, proc.returncode, cwd))
InstallationError: Command python setup.py egg_info failed with error code 1 in /tmp/pip-Mq6Yiv-build

Error - {"code": 40101, "message": "Missing request credentials", "stat": "FAIL"} How to resolve it?

import java.io.*;
import java.net.URL;
import java.net.HttpURLConnection;

public class duo {
    
    public static void main(String[] args) throws IOException, InterruptedException {
// Create a neat value object to hold the URL

  URL url;
      url = new URL("https://api-e9770554.duosecurity.com/admin/v1/users?username=#get_user.userid#");



// Open a connection(?) on the URL(??) and cast the response(???)
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();

// Now it's "open", we can set the request method, headers etc.
        connection.setRequestProperty("accept", "application/json");

// This line makes the request
        InputStream responseStream = connection.getInputStream();

 }

}

examples splunk.py is using python 2 import

examples splunk.py is using python 2 import

For proxy support

from urlparse import urlparse

should be for python 3

from urllib.parse import urlparse

see:

https://docs.python.org/2/library/urlparse.html

top of page says:

Note The urlparse module is renamed to urllib.parse in Python 3. The 2to3 tool will automatically adapt imports when converting your sources to Python 3.

python 3.7 docs:

https://docs.python.org/3.7/library/urllib.parse.html#module-urllib.parse

paging limit / offset error

I have code working on v.3 of the duo_client scripts. Bringing it up to v4, I'm receiving the following errors. The same error occurs with the user export script from the 'examples' directory. I just sync'd the new admin.py that was updated a little while ago.

`

-bash-4.1$ ./test_userdump.py

Admin API integration key ("DI..."): MY INTEGRATION KEY
integration secret key: MY SECRET KEY
API hostname ("api-....duosecurity.com"): MY API URL
Traceback (most recent call last):
File "./test_userdump.py", line 25, in
users = admin_api.get_users()
File "/path/to/admin.py", line 522, in get_users
(limit, offset) = self.normalize_paging_args(limit, offset)
File "/path/to/client.py", line 347, in normalize_paging_args
offset = '{}'.format(offset)
ValueError: zero length field name in format

`

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.