diff --git a/mitmproxy/cmdline.py b/mitmproxy/cmdline.py index 00d715112..696542f63 100644 --- a/mitmproxy/cmdline.py +++ b/mitmproxy/cmdline.py @@ -251,6 +251,9 @@ def get_common_options(args): replay_ignore_payload_params=args.replay_ignore_payload_params, replay_ignore_host=args.replay_ignore_host, + auth_nonanonymous = args.auth_nonanonymous, + auth_singleuser = args.auth_singleuser, + auth_htpasswd = args.auth_htpasswd, add_upstream_certs_to_client_chain = args.add_upstream_certs_to_client_chain, body_size_limit = body_size_limit, cadir = args.cadir, diff --git a/mitmproxy/flow/options.py b/mitmproxy/flow/options.py index f1f8c2ed3..726952e29 100644 --- a/mitmproxy/flow/options.py +++ b/mitmproxy/flow/options.py @@ -39,6 +39,9 @@ class Options(options.Options): replay_ignore_host=False, # type: bool # Proxy options + auth_nonanonymous=False, # type: bool + auth_singleuser=None, # type: Optional[str] + auth_htpasswd=None, # type: Optional[str] add_upstream_certs_to_client_chain=False, # type: bool body_size_limit=None, # type: Optional[int] cadir = cmdline.CA_DIR, # type: str @@ -93,6 +96,9 @@ class Options(options.Options): self.replay_ignore_host = replay_ignore_host # Proxy options + self.auth_nonanonymous = auth_nonanonymous + self.auth_singleuser = auth_singleuser + self.auth_htpasswd = auth_htpasswd self.add_upstream_certs_to_client_chain = add_upstream_certs_to_client_chain self.body_size_limit = body_size_limit self.cadir = cadir diff --git a/mitmproxy/proxy/config.py b/mitmproxy/proxy/config.py index ff133084e..bd9f135d7 100644 --- a/mitmproxy/proxy/config.py +++ b/mitmproxy/proxy/config.py @@ -70,15 +70,10 @@ def parse_upstream_auth(auth): class ProxyConfig: - def __init__( - self, - options, - authenticator=None, - ): + def __init__(self, options): self.options = options - self.authenticator = authenticator - + self.authenticator = None self.check_ignore = None self.check_tcp = None self.certstore = None @@ -88,6 +83,20 @@ class ProxyConfig: options.changed.connect(self.configure) def configure(self, options): + conflict = all( + [ + options.add_upstream_certs_to_client_chain, + options.ssl_verify_upstream_cert + ] + ) + if conflict: + raise exceptions.OptionsError( + "The verify-upstream-cert and add-upstream-certs-to-client-chain " + "options are mutually exclusive. If upstream certificates are verified " + "then extra upstream certificates are not available for inclusion " + "to the client chain." + ) + if options.ssl_verify_upstream_cert: self.openssl_verification_mode_server = SSL.VERIFY_PEER else: @@ -141,46 +150,46 @@ class ProxyConfig: if options.upstream_auth: self.upstream_auth = parse_upstream_auth(options.upstream_auth) - -def process_proxy_options(parser, options, args): - if args.add_upstream_certs_to_client_chain and args.ssl_verify_upstream_cert: - return parser.error( - "The verify-upstream-cert and add-upstream-certs-to-client-chain " - "options are mutually exclusive. If upstream certificates are verified " - "then extra upstream certificates are not available for inclusion " - "to the client chain." + self.authenticator = authentication.NullProxyAuth(None) + needsauth = any( + [ + options.auth_nonanonymous, + options.auth_singleuser, + options.auth_htpasswd + ] ) - if args.auth_nonanonymous or args.auth_singleuser or args.auth_htpasswd: - if args.transparent_proxy: - return parser.error("Proxy Authentication not supported in transparent mode.") - - if args.socks_proxy: - return parser.error( - "Proxy Authentication not supported in SOCKS mode. " - "https://github.com/mitmproxy/mitmproxy/issues/738" + if needsauth: + if options.mode == "transparent": + raise exceptions.OptionsError( + "Proxy Authentication not supported in transparent mode." + ) + elif options.mode == "socks5": + raise exceptions.OptionsError( + "Proxy Authentication not supported in SOCKS mode. " + "https://github.com/mitmproxy/mitmproxy/issues/738" + ) + elif options.auth_singleuser: + parts = options.auth_singleuser.split(':') + if len(parts) != 2: + raise exceptions.OptionsError( + "Invalid single-user specification. " + "Please use the format username:password" + ) + password_manager = authentication.PassManSingleUser(*parts) + elif options.auth_nonanonymous: + password_manager = authentication.PassManNonAnon() + elif options.auth_htpasswd: + try: + password_manager = authentication.PassManHtpasswd( + options.auth_htpasswd + ) + except ValueError as v: + raise exceptions.OptionsError(str(v)) + self.authenticator = authentication.BasicProxyAuth( + password_manager, + "mitmproxy" ) - if args.auth_singleuser: - if len(args.auth_singleuser.split(':')) != 2: - return parser.error( - "Invalid single-user specification. Please use the format username:password" - ) - username, password = args.auth_singleuser.split(':') - password_manager = authentication.PassManSingleUser(username, password) - elif args.auth_nonanonymous: - password_manager = authentication.PassManNonAnon() - elif args.auth_htpasswd: - try: - password_manager = authentication.PassManHtpasswd( - args.auth_htpasswd - ) - except ValueError as v: - return parser.error(v) - authenticator = authentication.BasicProxyAuth(password_manager, "mitmproxy") - else: - authenticator = authentication.NullProxyAuth(None) - return ProxyConfig( - options, - authenticator=authenticator, - ) +def process_proxy_options(parser, options, args): + return ProxyConfig(options) diff --git a/test/mitmproxy/test_protocol_http2.py b/test/mitmproxy/test_protocol_http2.py index e8866643a..a7a3ba3fa 100644 --- a/test/mitmproxy/test_protocol_http2.py +++ b/test/mitmproxy/test_protocol_http2.py @@ -106,9 +106,7 @@ class _Http2TestBase(object): def get_proxy_config(cls): opts = options.Options(listen_port=0, no_upstream_cert=False) opts.cadir = os.path.join(tempfile.gettempdir(), "mitmproxy") - d = dict( - authenticator=None, - ) + d = dict() return d, opts @property diff --git a/test/mitmproxy/test_proxy.py b/test/mitmproxy/test_proxy.py index 5cceb8c2d..4127a8893 100644 --- a/test/mitmproxy/test_proxy.py +++ b/test/mitmproxy/test_proxy.py @@ -103,7 +103,11 @@ class TestProcessProxyOptions: # self.assert_err("mutually exclusive", "-R", "http://localhost", "-T") def test_socks_auth(self): - self.assert_err("Proxy Authentication not supported in SOCKS mode.", "--socks", "--nonanonymous") + self.assert_err( + "Proxy Authentication not supported in SOCKS mode.", + "--socks", + "--nonanonymous" + ) def test_client_certs(self): with tutils.tmpdir() as cadir: diff --git a/test/mitmproxy/test_server.py b/test/mitmproxy/test_server.py index f036fefdc..b8b057fd2 100644 --- a/test/mitmproxy/test_server.py +++ b/test/mitmproxy/test_server.py @@ -298,13 +298,8 @@ class TestHTTP(tservers.HTTPProxyTest, CommonMixin, AppMixin): class TestHTTPAuth(tservers.HTTPProxyTest): - authenticator = http.authentication.BasicProxyAuth( - http.authentication.PassManSingleUser( - "test", - "test"), - "realm") - def test_auth(self): + self.master.options.auth_singleuser = "test:test" assert self.pathod("202").status_code == 407 p = self.pathoc() ret = p.request(""" diff --git a/test/mitmproxy/tservers.py b/test/mitmproxy/tservers.py index 8df30e347..495765da8 100644 --- a/test/mitmproxy/tservers.py +++ b/test/mitmproxy/tservers.py @@ -78,7 +78,6 @@ class ProxyTestBase(object): ssl = None ssloptions = False no_upstream_cert = False - authenticator = None masterclass = TestMaster add_upstream_certs_to_client_chain = False @@ -120,9 +119,7 @@ class ProxyTestBase(object): @classmethod def get_proxy_config(cls): cls.cadir = os.path.join(tempfile.gettempdir(), "mitmproxy") - cnf = dict( - authenticator = cls.authenticator, - ) + cnf = dict() return cnf, options.Options( listen_port=0, cadir=cls.cadir,