duosecurity / duo_client_python Goto Github PK
View Code? Open in Web Editor NEWPython library for interacting with the Duo Auth, Admin, and Accounts APIs
Home Page: https://duo.com/docs/
License: Other
Python library for interacting with the Duo Auth, Admin, and Accounts APIs
Home Page: https://duo.com/docs/
License: Other
thanks.
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
duo_client_python/duo_client/client.py
Line 347 in c624284
FIDO U2F tokens are currently supported via the browser but not via the client API.
This renders the user experience (and in some cases security offered) inconsistent between authentication environments.
Python U2F device authentication could be done via https://github.com/Yubico/python-u2flib-host
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
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.
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?
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.
Would be great if there was a function in the admin client that covered this endpoint.
/admin/v1/endpoints/[epkey]
examples splunk.py is using python 2 import
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
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();
}
}
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
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
Requiring that I install nose
in order to use the duo client is a bit weird. Can we get this moved from install_requires
to tests_require
? Thanks!
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.
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
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!
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
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!
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.
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!
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:
pip install duo_client
Update Admin should be able to update any field in administrators. Specifically the status.
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
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
duo_client_python/duo_client/admin.py
Line 448 in 7c5b115
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
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?
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
Add methods to get and set billing edition
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('*', '[^.]*')
Traceback (most recent call last):
File "report_users_and_phones.py", line 7, in
import duo_client
ModuleNotFoundError: No module named 'duo_client'
It would be nice if there was a standard setup.py per this: http://docs.python.org/release/2.2p1/inst/standard-install.html
Pretty low priority though.
Occasionally I receive a 429 error from Duo and I haven't been able to find a specific limit in the docs. What, if any, are the request limits? And does the python package have a retry method?
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.
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
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.
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.
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.
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.
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
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
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
Hi there, a very simple issue, the add_admin function is missing the API "role" parameter for defining roles other than Admin.
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
duo_client_python/duo_client/admin.py
Line 453 in 7c5b115
I'd like to be able to use this in a python 3 project.
duo_client_python/duo_client/client.py
Line 499 in d08126e
The metadata is stored at response.metadata is it not?
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
#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.
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'
I would like support for Trust Monitor Data by implementing the trust_monitor endpoint.
Please add API endpoints for DUO SSO integration automation. Currently only DAG is supported and you are EOL the DAG this month.
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.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.