diff options
author | Aldo Cortesi <aldo@nullcube.com> | 2017-03-07 20:18:30 +1300 |
---|---|---|
committer | Aldo Cortesi <aldo@nullcube.com> | 2017-03-07 20:18:30 +1300 |
commit | aed780bf48f6231e63a2b193318bc234152e2743 (patch) | |
tree | b0eb10d80edc2205df5aa6b0a3fba09093382599 | |
parent | b0ba76559869053e49b9c11b826a542b4885b49d (diff) | |
download | mitmproxy-aed780bf48f6231e63a2b193318bc234152e2743.tar.gz mitmproxy-aed780bf48f6231e63a2b193318bc234152e2743.tar.bz2 mitmproxy-aed780bf48f6231e63a2b193318bc234152e2743.zip |
Change the way proxy authetication is specified
We now have one option "proxyauth". If this is "any", we accept any
credentials, if it starts with an @ it's treated as a path to an htpasswd file,
if it is of the form username:password it's a single-user credential.
-rw-r--r-- | mitmproxy/addons/proxyauth.py | 46 | ||||
-rw-r--r-- | mitmproxy/options.py | 17 | ||||
-rw-r--r-- | mitmproxy/tools/cmdline.py | 4 | ||||
-rw-r--r-- | test/mitmproxy/addons/test_proxyauth.py | 38 | ||||
-rw-r--r-- | test/mitmproxy/proxy/test_server.py | 4 |
5 files changed, 51 insertions, 58 deletions
diff --git a/mitmproxy/addons/proxyauth.py b/mitmproxy/addons/proxyauth.py index 18a85866..61477658 100644 --- a/mitmproxy/addons/proxyauth.py +++ b/mitmproxy/addons/proxyauth.py @@ -114,30 +114,28 @@ class ProxyAuth: # Handlers 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.htpasswd = None + if "proxyauth" in updated: + self.nonanonymous = False + self.singleuser = None + self.htpasswd = None + if options.proxyauth: + if options.proxyauth == "any": + self.nonanonymous = True + elif options.proxyauth.startswith("@"): + p = options.proxyauth[1:] + try: + self.htpasswd = passlib.apache.HtpasswdFile(p) + except (ValueError, OSError) as v: + raise exceptions.OptionsError( + "Could not open htpasswd file: %s" % p + ) + else: + parts = options.proxyauth.split(':') + if len(parts) != 2: + raise exceptions.OptionsError( + "Invalid single-user auth specification." + ) + self.singleuser = parts if "mode" in updated: self.mode = options.mode if self.enabled(): diff --git a/mitmproxy/options.py b/mitmproxy/options.py index cee80158..a754325a 100644 --- a/mitmproxy/options.py +++ b/mitmproxy/options.py @@ -203,21 +203,16 @@ class Options(optmanager.OptManager): # Proxy options self.add_option( - "auth_nonanonymous", False, bool, - "Allow access to any user long as a credentials are specified." - ) - self.add_option( - "auth_singleuser", None, Optional[str], + "proxyauth", None, Optional[str], """ - Allows access to a a single user, specified in the form - username:password. + Require authentication before proxying requests. If the value is + "any", we prompt for authentication, but permit any values. If it + starts with an "@", it is treated as a path to an Apache htpasswd + file. If its is of the form "username:password", it is treated as a + single-user credential. """ ) self.add_option( - "auth_htpasswd", None, Optional[str], - "Allow access to users specified in an Apache htpasswd file." - ) - self.add_option( "add_upstream_certs_to_client_chain", False, bool, """ Add all certificates of the upstream server to the certificate chain diff --git a/mitmproxy/tools/cmdline.py b/mitmproxy/tools/cmdline.py index bb33c1e4..fcf9ecaf 100644 --- a/mitmproxy/tools/cmdline.py +++ b/mitmproxy/tools/cmdline.py @@ -107,9 +107,7 @@ def common_options(parser, opts): used for authenticating them. """ ).add_mutually_exclusive_group() - opts.make_parser(group, "auth_nonanonymous") - opts.make_parser(group, "auth_singleuser", metavar="USER:PASS") - opts.make_parser(group, "auth_htpasswd", metavar="PATH") + opts.make_parser(group, "proxyauth", metavar="SPEC") def mitmproxy(opts): diff --git a/test/mitmproxy/addons/test_proxyauth.py b/test/mitmproxy/addons/test_proxyauth.py index dd5829ab..14782755 100644 --- a/test/mitmproxy/addons/test_proxyauth.py +++ b/test/mitmproxy/addons/test_proxyauth.py @@ -28,40 +28,43 @@ def test_configure(): up = proxyauth.ProxyAuth() with taddons.context() as ctx: with pytest.raises(exceptions.OptionsError): - ctx.configure(up, auth_singleuser="foo") + ctx.configure(up, proxyauth="foo") - ctx.configure(up, auth_singleuser="foo:bar") + ctx.configure(up, proxyauth="foo:bar") assert up.singleuser == ["foo", "bar"] - ctx.configure(up, auth_singleuser=None) + ctx.configure(up, proxyauth=None) assert up.singleuser is None - ctx.configure(up, auth_nonanonymous=True) + ctx.configure(up, proxyauth="any") assert up.nonanonymous - ctx.configure(up, auth_nonanonymous=False) + ctx.configure(up, proxyauth=None) assert not up.nonanonymous with pytest.raises(exceptions.OptionsError): - ctx.configure(up, auth_htpasswd=tutils.test_data.path("mitmproxy/net/data/server.crt")) + ctx.configure( + up, + proxyauth= "@" + tutils.test_data.path("mitmproxy/net/data/server.crt") + ) with pytest.raises(exceptions.OptionsError): - ctx.configure(up, auth_htpasswd="nonexistent") + ctx.configure(up, proxyauth="@nonexistent") ctx.configure( up, - auth_htpasswd=tutils.test_data.path( + proxyauth= "@" + tutils.test_data.path( "mitmproxy/net/data/htpasswd" ) ) assert up.htpasswd assert up.htpasswd.check_password("test", "test") assert not up.htpasswd.check_password("test", "foo") - ctx.configure(up, auth_htpasswd=None) + ctx.configure(up, proxyauth=None) assert not up.htpasswd with pytest.raises(exceptions.OptionsError): - ctx.configure(up, auth_nonanonymous=True, mode="transparent") + ctx.configure(up, proxyauth="any", mode="transparent") with pytest.raises(exceptions.OptionsError): - ctx.configure(up, auth_nonanonymous=True, mode="socks5") + ctx.configure(up, proxyauth="any", mode="socks5") ctx.configure(up, mode="regular") assert up.mode == "regular" @@ -70,7 +73,7 @@ def test_configure(): def test_check(): up = proxyauth.ProxyAuth() with taddons.context() as ctx: - ctx.configure(up, auth_nonanonymous=True, mode="regular") + ctx.configure(up, proxyauth="any", mode="regular") f = tflow.tflow() assert not up.check(f) f.request.headers["Proxy-Authorization"] = proxyauth.mkauth( @@ -86,18 +89,17 @@ def test_check(): ) assert not up.check(f) - ctx.configure(up, auth_nonanonymous=False, auth_singleuser="test:test") + ctx.configure(up, proxyauth="test:test") f.request.headers["Proxy-Authorization"] = proxyauth.mkauth( "test", "test" ) assert up.check(f) - ctx.configure(up, auth_nonanonymous=False, auth_singleuser="test:foo") + ctx.configure(up, proxyauth="test:foo") assert not up.check(f) ctx.configure( up, - auth_singleuser=None, - auth_htpasswd=tutils.test_data.path( + proxyauth="@" + tutils.test_data.path( "mitmproxy/net/data/htpasswd" ) ) @@ -114,7 +116,7 @@ def test_check(): def test_authenticate(): up = proxyauth.ProxyAuth() with taddons.context() as ctx: - ctx.configure(up, auth_nonanonymous=True, mode="regular") + ctx.configure(up, proxyauth="any", mode="regular") f = tflow.tflow() assert not f.response @@ -147,7 +149,7 @@ def test_authenticate(): def test_handlers(): up = proxyauth.ProxyAuth() with taddons.context() as ctx: - ctx.configure(up, auth_nonanonymous=True, mode="regular") + ctx.configure(up, proxyauth="any", mode="regular") f = tflow.tflow() assert not f.response diff --git a/test/mitmproxy/proxy/test_server.py b/test/mitmproxy/proxy/test_server.py index b90840ab..aa45761a 100644 --- a/test/mitmproxy/proxy/test_server.py +++ b/test/mitmproxy/proxy/test_server.py @@ -302,7 +302,7 @@ class TestHTTP(tservers.HTTPProxyTest, CommonMixin): class TestHTTPAuth(tservers.HTTPProxyTest): def test_auth(self): self.master.addons.add(proxyauth.ProxyAuth()) - self.master.options.auth_singleuser = "test:test" + self.master.options.proxyauth = "test:test" assert self.pathod("202").status_code == 407 p = self.pathoc() with p.connect(): @@ -321,7 +321,7 @@ class TestHTTPAuth(tservers.HTTPProxyTest): class TestHTTPReverseAuth(tservers.ReverseProxyTest): def test_auth(self): self.master.addons.add(proxyauth.ProxyAuth()) - self.master.options.auth_singleuser = "test:test" + self.master.options.proxyauth = "test:test" assert self.pathod("202").status_code == 401 p = self.pathoc() with p.connect(): |