summaryrefslogtreecommitdiff
path: root/test_duo_openvpn.py
diff options
context:
space:
mode:
authorPete <petiepooo@gmail.com>2019-12-18 12:03:17 -0500
committerXander Desai <xdesai@duosecurity.com>2019-12-18 12:03:17 -0500
commitd0d47c7959f4c5193b767ddea8b0affc25ca40f0 (patch)
tree51687dd2b779237d1acd2363cd8ad0412aaf14e9 /test_duo_openvpn.py
parent8c4d7c4affad93cbdc70180d0eb11a4869e5b298 (diff)
downloadopenvpn-duo-plugin-d0d47c7959f4c5193b767ddea8b0affc25ca40f0.tar.gz
openvpn-duo-plugin-d0d47c7959f4c5193b767ddea8b0affc25ca40f0.zip
Python3 compatibility updates (#28)
* WIP: fix imports and exception calls for python3 * fix remaining utf-8 encoding issues * fix init trying to return a value * change expected control checks to bytes * make comparison of request params non-ordered python3's url request handler likes to reorder the parameters its given this breaks the params out and checks each separately * refactor to simplify params comparisons * FIX: decode auth bytes back to a utf-8 string * FIX: also decode response data bytes to utf-8 * FIX: do not decode response data if already a str * enhance existing test to ensure auth is str no bytes * change test req and import from mox to mox3 * add additional python versions to CI config * fix failing 3.7 travis ci build * Apply changes to duo_openvpn.py similar to what we do in duo_client_python * Apply changes to https_wrapper similar to what we do in duo_client_python * Fixup the import bugs * Use six for StringIO import * Include six for py2->py3 compat layer * use explicit decoding on control file data * Consistent encoding and updated variable names for clarity * Revert variable names back again.
Diffstat (limited to 'test_duo_openvpn.py')
-rw-r--r--test_duo_openvpn.py44
1 files changed, 29 insertions, 15 deletions
diff --git a/test_duo_openvpn.py b/test_duo_openvpn.py
index df13d10..3930af8 100644
--- a/test_duo_openvpn.py
+++ b/test_duo_openvpn.py
@@ -1,11 +1,11 @@
-import StringIO
import email.utils
import json
import os
import tempfile
import unittest
-import mox
+from mox3 import mox
+import six
import duo_openvpn
@@ -19,7 +19,7 @@ def mock_client_factory(mock):
class MockClient(duo_openvpn.Client):
def __init__(self, *args, **kwargs):
mock.duo_client_init(*args, **kwargs)
- return super(MockClient, self).__init__(*args, **kwargs)
+ super(MockClient, self).__init__(*args, **kwargs)
def set_proxy(self, *args, **kwargs):
mock.duo_client_set_proxy(*args, **kwargs)
@@ -30,7 +30,7 @@ def mock_client_factory(mock):
return MockClient
-class MockResponse(StringIO.StringIO, object):
+class MockResponse(six.StringIO, object):
def __init__(self, status, body, reason='some reason'):
self.status = status
self.reason = reason
@@ -80,6 +80,8 @@ class TestIntegration(unittest.TestCase):
control.seek(0, os.SEEK_SET)
output = control.read()
+ if not isinstance(output, six.text_type):
+ output = output.decode('utf-8')
self.assertEqual(expected_control, output)
if expected_control == '1':
self.assertEqual(0, cm.exception.args[0])
@@ -107,12 +109,18 @@ class TestIntegration(unittest.TestCase):
)
return environ
- def expect_request(self, method, path, params, response=None, raises=None):
- self.expected_calls.request(method, path, params, {
+ def compare_params(self, recv_params, sent_params):
+ stanzas = sent_params.split('&')
+ return len(recv_params.split('&')) == len(stanzas) and all([s in recv_params for s in stanzas])
+
+ def expect_request(self, method, path, params, params_func=None, response=None, raises=None):
+ if params_func == None:
+ params_func = lambda p: self.compare_params(p, self.EXPECTED_PREAUTH_PARAMS)
+ self.expected_calls.request(method, path, mox.Func(params_func), {
'User-Agent': self.EXPECTED_USER_AGENT,
'Host': self.HOST,
'Content-type': 'application/x-www-form-urlencoded',
- 'Authorization': mox.Func((lambda s: s.startswith('Basic '))),
+ 'Authorization': mox.Func((lambda s: s.startswith('Basic ') and not s.startswith('Basic b\''))),
'Date': mox.Func((lambda s: bool(email.utils.parsedate_tz(s))))
},
)
@@ -146,6 +154,7 @@ class TestIntegration(unittest.TestCase):
method='POST',
path=path,
params=self.EXPECTED_AUTH_PARAMS,
+ params_func = lambda p: self.compare_params(p, self.EXPECTED_AUTH_PARAMS),
response=MockResponse(
status=200,
body=json.dumps({
@@ -279,6 +288,7 @@ class TestIntegration(unittest.TestCase):
method='POST',
path=self.EXPECTED_AUTH_PATH,
params=self.EXPECTED_AUTH_PARAMS,
+ params_func = lambda p: self.compare_params(p, self.EXPECTED_AUTH_PARAMS),
response=MockResponse(
status=200,
body=json.dumps({
@@ -301,6 +311,7 @@ class TestIntegration(unittest.TestCase):
method='POST',
path=self.EXPECTED_AUTH_PATH,
params=self.EXPECTED_AUTH_PARAMS,
+ params_func = lambda p: self.compare_params(p, self.EXPECTED_AUTH_PARAMS),
response=MockResponse(
status=200,
body=json.dumps({
@@ -323,6 +334,7 @@ class TestIntegration(unittest.TestCase):
method='POST',
path=self.EXPECTED_AUTH_PATH,
params=self.EXPECTED_AUTH_PARAMS,
+ params_func = lambda p: self.compare_params(p, self.EXPECTED_AUTH_PARAMS),
raises=Exception('whoops'),
)
self.assert_auth(
@@ -331,13 +343,15 @@ class TestIntegration(unittest.TestCase):
)
def test_auth_no_ipaddr(self):
+ preauth_noip_params='ipaddr=0.0.0.0' \
+ '&user=expected+username'
environ = self.normal_environ()
environ.pop('ipaddr')
self.expect_request(
method='POST',
path=self.EXPECTED_PREAUTH_PATH,
- params='ipaddr=0.0.0.0'
- '&user=expected+username',
+ params=preauth_noip_params,
+ params_func = lambda p: self.compare_params(p, preauth_noip_params),
response=MockResponse(
status=200,
body=json.dumps({
@@ -350,15 +364,15 @@ class TestIntegration(unittest.TestCase):
}),
),
)
+ auth_noip_params='auto=expected+passcode' \
+ '&ipaddr=0.0.0.0' \
+ '&user=expected+username' \
+ '&factor=auto'
self.expect_request(
method='POST',
path=self.EXPECTED_AUTH_PATH,
- params=(
- 'auto=expected+passcode'
- '&ipaddr=0.0.0.0'
- '&user=expected+username'
- '&factor=auto'
- ),
+ params=auth_noip_params,
+ params_func = lambda p: self.compare_params(p, auth_noip_params),
response=MockResponse(
status=200,
body=json.dumps({