aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--mitmproxy/protocol/http.py22
-rw-r--r--mitmproxy/proxy/config.py14
-rw-r--r--netlib/http/authentication.py16
-rw-r--r--test/mitmproxy/test_server.py16
4 files changed, 55 insertions, 13 deletions
diff --git a/mitmproxy/protocol/http.py b/mitmproxy/protocol/http.py
index 2c70f288..309a0844 100644
--- a/mitmproxy/protocol/http.py
+++ b/mitmproxy/protocol/http.py
@@ -132,6 +132,8 @@ class HttpLayer(base.Layer):
# We cannot rely on server_conn.tls_established,
# see https://github.com/mitmproxy/mitmproxy/issues/925
self.__initial_server_tls = None
+ # Requests happening after CONNECT do not need Proxy-Authorization headers.
+ self.http_authenticated = False
def __call__(self):
if self.mode == "transparent":
@@ -146,7 +148,7 @@ class HttpLayer(base.Layer):
# Proxy Authentication conceptually does not work in transparent mode.
# We catch this misconfiguration on startup. Here, we sort out requests
# after a successful CONNECT request (which do not need to be validated anymore)
- if self.mode != "transparent" and not self.authenticate(request):
+ if not (self.http_authenticated or self.authenticate(request)):
return
# Make sure that the incoming request matches our expectations
@@ -239,6 +241,7 @@ class HttpLayer(base.Layer):
return self.set_server(address)
def handle_regular_mode_connect(self, request):
+ self.http_authenticated = True
self.set_server((request.host, request.port))
self.send_response(models.make_connect_response(request.data.http_version))
layer = self.ctx.next_layer(self)
@@ -397,10 +400,17 @@ class HttpLayer(base.Layer):
if self.config.authenticator.authenticate(request.headers):
self.config.authenticator.clean(request.headers)
else:
- self.send_response(models.make_error_response(
- 407,
- "Proxy Authentication Required",
- http.Headers(**self.config.authenticator.auth_challenge_headers())
- ))
+ if self.mode == "transparent":
+ self.send_response(models.make_error_response(
+ 401,
+ "Authentication Required",
+ http.Headers(**self.config.authenticator.auth_challenge_headers())
+ ))
+ else:
+ self.send_response(models.make_error_response(
+ 407,
+ "Proxy Authentication Required",
+ http.Headers(**self.config.authenticator.auth_challenge_headers())
+ ))
return False
return True
diff --git a/mitmproxy/proxy/config.py b/mitmproxy/proxy/config.py
index cf75830a..26f6a236 100644
--- a/mitmproxy/proxy/config.py
+++ b/mitmproxy/proxy/config.py
@@ -179,7 +179,13 @@ class ProxyConfig:
)
except ValueError as v:
raise exceptions.OptionsError(str(v))
- self.authenticator = authentication.BasicProxyAuth(
- password_manager,
- "mitmproxy"
- )
+ if options.mode == "reverse":
+ self.authenticator = authentication.BasicWebsiteAuth(
+ password_manager,
+ self.upstream_server.address
+ )
+ else:
+ self.authenticator = authentication.BasicProxyAuth(
+ password_manager,
+ "mitmproxy"
+ ) \ No newline at end of file
diff --git a/netlib/http/authentication.py b/netlib/http/authentication.py
index 38ea46d6..58fc9bdc 100644
--- a/netlib/http/authentication.py
+++ b/netlib/http/authentication.py
@@ -50,9 +50,9 @@ class NullProxyAuth(object):
return {}
-class BasicProxyAuth(NullProxyAuth):
- CHALLENGE_HEADER = 'Proxy-Authenticate'
- AUTH_HEADER = 'Proxy-Authorization'
+class BasicAuth(NullProxyAuth):
+ CHALLENGE_HEADER = None
+ AUTH_HEADER = None
def __init__(self, password_manager, realm):
NullProxyAuth.__init__(self, password_manager)
@@ -80,6 +80,16 @@ class BasicProxyAuth(NullProxyAuth):
return {self.CHALLENGE_HEADER: 'Basic realm="%s"' % self.realm}
+class BasicWebsiteAuth(BasicAuth):
+ CHALLENGE_HEADER = 'WWW-Authenticate'
+ AUTH_HEADER = 'Authorization'
+
+
+class BasicProxyAuth(BasicAuth):
+ CHALLENGE_HEADER = 'Proxy-Authenticate'
+ AUTH_HEADER = 'Proxy-Authorization'
+
+
class PassMan(object):
def test(self, username_, password_token_):
diff --git a/test/mitmproxy/test_server.py b/test/mitmproxy/test_server.py
index 78e9b5c7..78a97dc3 100644
--- a/test/mitmproxy/test_server.py
+++ b/test/mitmproxy/test_server.py
@@ -313,6 +313,22 @@ class TestHTTPAuth(tservers.HTTPProxyTest):
assert ret.status_code == 202
+class TestHTTPReverseAuth(tservers.ReverseProxyTest):
+ def test_auth(self):
+ self.master.options.auth_singleuser = "test:test"
+ assert self.pathod("202").status_code == 401
+ p = self.pathoc()
+ ret = p.request("""
+ get
+ '/p/202'
+ h'%s'='%s'
+ """ % (
+ http.authentication.BasicWebsiteAuth.AUTH_HEADER,
+ authentication.assemble_http_basic_auth("basic", "test", "test")
+ ))
+ assert ret.status_code == 202
+
+
class TestHTTPS(tservers.HTTPProxyTest, CommonMixin, TcpMixin):
ssl = True
ssloptions = pathod.SSLOptions(request_client_cert=True)