From e644d2167c5fe591d475ca1a371690f89a6f0878 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sun, 13 Nov 2016 12:32:20 +1300 Subject: [PATCH] stub out proxyauth addon Stub out basic workings, add and test configure event. --- mitmproxy/addons/proxyauth.py | 68 +++++++++++++++++++++++++ test/mitmproxy/addons/test_proxyauth.py | 53 +++++++++++++++++++ 2 files changed, 121 insertions(+) create mode 100644 mitmproxy/addons/proxyauth.py create mode 100644 test/mitmproxy/addons/test_proxyauth.py diff --git a/mitmproxy/addons/proxyauth.py b/mitmproxy/addons/proxyauth.py new file mode 100644 index 000000000..fc68de71e --- /dev/null +++ b/mitmproxy/addons/proxyauth.py @@ -0,0 +1,68 @@ +import binascii + +import passlib.apache + +from mitmproxy import exceptions + + +def parse_http_basic_auth(s): + words = s.split() + if len(words) != 2: + return None + scheme = words[0] + try: + user = binascii.a2b_base64(words[1]).decode("utf8", "replace") + except binascii.Error: + return None + parts = user.split(':') + if len(parts) != 2: + return None + return scheme, parts[0], parts[1] + + +def assemble_http_basic_auth(scheme, username, password): + v = binascii.b2a_base64( + (username + ":" + password).encode("utf8") + ).decode("ascii") + return scheme + " " + v + + +class ProxyAuth: + def __init__(self): + self.nonanonymous = False + self.htpasswd = None + self.singleuser = None + + def configure(self, options, updated): + if "auth_nonanonymous" in updated: + self.nonanonymous = options.auth_nonanonymous + if "auth_singleuser" in updated: + if options.auth_singleuser: + parts = options.auth_singleuser.split(':') + if len(parts) != 2: + raise exceptions.OptionsError( + "Invalid single-user auth specification." + ) + self.singleuser = parts + else: + self.singleuser = None + if "auth_htpasswd" in updated: + if options.auth_htpasswd: + try: + self.htpasswd = passlib.apache.HtpasswdFile( + options.auth_htpasswd + ) + except (ValueError, OSError) as v: + raise exceptions.OptionsError( + "Could not open htpasswd file: %s" % v + ) + else: + self.auth_htpasswd = None + + def http_connect(self, f): + # mode = regular + pass + + def http_request(self, f): + # mode = regular, no via + pass diff --git a/test/mitmproxy/addons/test_proxyauth.py b/test/mitmproxy/addons/test_proxyauth.py new file mode 100644 index 000000000..e9dcf7bfc --- /dev/null +++ b/test/mitmproxy/addons/test_proxyauth.py @@ -0,0 +1,53 @@ +import binascii + +from mitmproxy import exceptions +from mitmproxy.test import taddons +from mitmproxy.test import tflow +from mitmproxy.test import tutils +from mitmproxy.addons import proxyauth + + +def test_parse_http_basic_auth(): + vals = ("basic", "foo", "bar") + assert proxyauth.parse_http_basic_auth( + proxyauth.assemble_http_basic_auth(*vals) + ) == vals + assert not proxyauth.parse_http_basic_auth("") + assert not proxyauth.parse_http_basic_auth("foo bar") + v = "basic " + binascii.b2a_base64(b"foo").decode("ascii") + assert not proxyauth.parse_http_basic_auth(v) + + +def test_configure(): + up = proxyauth.ProxyAuth() + with taddons.context() as ctx: + tutils.raises( + exceptions.OptionsError, + ctx.configure, up, auth_singleuser="foo" + ) + + ctx.configure(up, auth_singleuser="foo:bar") + assert up.singleuser == ["foo", "bar"] + + ctx.configure(up, auth_singleuser=None) + assert up.singleuser is None + + ctx.configure(up, auth_nonanonymous=True) + assert up.nonanonymous + ctx.configure(up, auth_nonanonymous=False) + assert not up.nonanonymous + + tutils.raises( + exceptions.OptionsError, + ctx.configure, + up, + auth_htpasswd = tutils.test_data.path( + "mitmproxy/net/data/server.crt" + ) + ) + tutils.raises( + exceptions.OptionsError, + ctx.configure, + up, + auth_htpasswd = "nonexistent" + )