diff options
Diffstat (limited to 'duo_openvpn.py')
-rwxr-xr-x | duo_openvpn.py | 55 |
1 files changed, 39 insertions, 16 deletions
diff --git a/duo_openvpn.py b/duo_openvpn.py index a82839a..cb01827 100755 --- a/duo_openvpn.py +++ b/duo_openvpn.py @@ -8,12 +8,14 @@ __version__ = '2.2' import base64 import email.utils -import httplib import os import socket import sys import syslog -import urllib + +import six +from six.moves import http_client +from six.moves.urllib.parse import quote, urlencode def log(msg): msg = 'Duo OpenVPN: %s' % msg @@ -24,7 +26,7 @@ try: import hmac import json from https_wrapper import CertValidatingHTTPSConnection -except ImportError, e: +except ImportError as e: log('ImportError: %s' % e) log('Please make sure you\'re running Python 2.6 or newer') raise @@ -44,8 +46,8 @@ def canon_params(params): # http://tools.ietf.org/html/rfc5849#section-3.4.1.3.2 args = [] for (key, vals) in sorted( - (urllib.quote(key, '~'), vals) for (key, vals) in params.items()): - for val in sorted(urllib.quote(val, '~') for val in vals): + (quote(key, '~'), vals) for (key, vals) in params.items()): + for val in sorted(quote(val, '~') for val in vals): args.append('%s=%s' % (key, val)) return '&'.join(args) @@ -73,11 +75,24 @@ def sign(ikey, skey, method, host, uri, date, sig_version, params): Return basic authorization header line with a Duo Web API signature. """ canonical = canonicalize(method, host, uri, params, date, sig_version) - if isinstance(skey, unicode): + + if isinstance(skey, six.text_type): skey = skey.encode('utf-8') + if isinstance(canonical, six.text_type): + canonical = canonical.encode('utf-8') + sig = hmac.new(skey, canonical, hashlib.sha1) auth = '%s:%s' % (ikey, sig.hexdigest()) - return 'Basic %s' % base64.b64encode(auth) + + if isinstance(auth, six.text_type): + auth = auth.encode('utf-8') + + b64 = base64.b64encode(auth) + if not isinstance(b64, six.text_type): + b64 = b64.decode('utf-8') + + return 'Basic %s' % b64 + def normalize_params(params): """ @@ -87,16 +102,19 @@ def normalize_params(params): # urllib cannot handle unicode strings properly. quote() excepts, # and urlencode() replaces them with '?'. def encode(value): - if isinstance(value, unicode): + if isinstance(value, six.text_type): return value.encode("utf-8") return value + def to_list(value): - if value is None or isinstance(value, basestring): + if value is None or isinstance(value, six.string_types): return [value] return value + return dict( (encode(key), [encode(v) for v in to_list(value)]) - for (key, value) in params.items()) + for (key, value) in list(params.items())) + class Client(object): sig_version = 1 @@ -163,11 +181,11 @@ class Client(object): if method in ['POST', 'PUT']: headers['Content-type'] = 'application/x-www-form-urlencoded' - body = urllib.urlencode(params, doseq=True) + body = urlencode(params, doseq=True) uri = path else: body = None - uri = path + '?' + urllib.urlencode(params, doseq=True) + uri = path + '?' + urlencode(params, doseq=True) return self._make_request(method, uri, body, headers) @@ -192,9 +210,9 @@ class Client(object): # Create outer HTTP(S) connection. if self.ca_certs == 'HTTP': - conn = httplib.HTTPConnection(host, port) + conn = http_client.HTTPConnection(host, port) elif self.ca_certs == 'DISABLE': - conn = httplib.HTTPSConnection(host, port) + conn = http_client.HTTPSConnection(host, port) else: conn = CertValidatingHTTPSConnection(host, port, @@ -255,6 +273,10 @@ class Client(object): error.reason = response.reason error.data = data raise error + + if not isinstance(data, six.text_type): + data = data.decode('utf-8') + if response.status != 200: try: data = json.loads(data) @@ -391,7 +413,7 @@ def main(Client=Client, environ=os.environ): try: default_factor = preauth(client, control, username, ipaddr) - except Exception, e: + except Exception as e: log(str(e)) failure(control) @@ -404,11 +426,12 @@ def main(Client=Client, environ=os.environ): try: auth(client, control, username, password, ipaddr) - except Exception, e: + except Exception as e: log(str(e)) failure(control) failure(control) + if __name__ == '__main__': main() |