mirror of
https://github.com/Grasscutters/mitmproxy.git
synced 2025-01-30 23:09:44 +00:00
add basic auth support for reverse proxy mode
This commit is contained in:
parent
a0391db1ae
commit
a9401472cd
@ -132,6 +132,8 @@ class HttpLayer(base.Layer):
|
|||||||
# We cannot rely on server_conn.tls_established,
|
# We cannot rely on server_conn.tls_established,
|
||||||
# see https://github.com/mitmproxy/mitmproxy/issues/925
|
# see https://github.com/mitmproxy/mitmproxy/issues/925
|
||||||
self.__initial_server_tls = None
|
self.__initial_server_tls = None
|
||||||
|
# Requests happening after CONNECT do not need Proxy-Authorization headers.
|
||||||
|
self.http_authenticated = False
|
||||||
|
|
||||||
def __call__(self):
|
def __call__(self):
|
||||||
if self.mode == "transparent":
|
if self.mode == "transparent":
|
||||||
@ -146,7 +148,7 @@ class HttpLayer(base.Layer):
|
|||||||
# Proxy Authentication conceptually does not work in transparent mode.
|
# Proxy Authentication conceptually does not work in transparent mode.
|
||||||
# We catch this misconfiguration on startup. Here, we sort out requests
|
# We catch this misconfiguration on startup. Here, we sort out requests
|
||||||
# after a successful CONNECT request (which do not need to be validated anymore)
|
# 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
|
return
|
||||||
|
|
||||||
# Make sure that the incoming request matches our expectations
|
# Make sure that the incoming request matches our expectations
|
||||||
@ -239,6 +241,7 @@ class HttpLayer(base.Layer):
|
|||||||
return self.set_server(address)
|
return self.set_server(address)
|
||||||
|
|
||||||
def handle_regular_mode_connect(self, request):
|
def handle_regular_mode_connect(self, request):
|
||||||
|
self.http_authenticated = True
|
||||||
self.set_server((request.host, request.port))
|
self.set_server((request.host, request.port))
|
||||||
self.send_response(models.make_connect_response(request.data.http_version))
|
self.send_response(models.make_connect_response(request.data.http_version))
|
||||||
layer = self.ctx.next_layer(self)
|
layer = self.ctx.next_layer(self)
|
||||||
@ -397,10 +400,17 @@ class HttpLayer(base.Layer):
|
|||||||
if self.config.authenticator.authenticate(request.headers):
|
if self.config.authenticator.authenticate(request.headers):
|
||||||
self.config.authenticator.clean(request.headers)
|
self.config.authenticator.clean(request.headers)
|
||||||
else:
|
else:
|
||||||
self.send_response(models.make_error_response(
|
if self.mode == "transparent":
|
||||||
407,
|
self.send_response(models.make_error_response(
|
||||||
"Proxy Authentication Required",
|
401,
|
||||||
http.Headers(**self.config.authenticator.auth_challenge_headers())
|
"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 False
|
||||||
return True
|
return True
|
||||||
|
@ -179,7 +179,13 @@ class ProxyConfig:
|
|||||||
)
|
)
|
||||||
except ValueError as v:
|
except ValueError as v:
|
||||||
raise exceptions.OptionsError(str(v))
|
raise exceptions.OptionsError(str(v))
|
||||||
self.authenticator = authentication.BasicProxyAuth(
|
if options.mode == "reverse":
|
||||||
password_manager,
|
self.authenticator = authentication.BasicWebsiteAuth(
|
||||||
"mitmproxy"
|
password_manager,
|
||||||
)
|
self.upstream_server.address
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self.authenticator = authentication.BasicProxyAuth(
|
||||||
|
password_manager,
|
||||||
|
"mitmproxy"
|
||||||
|
)
|
@ -50,9 +50,9 @@ class NullProxyAuth(object):
|
|||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
|
||||||
class BasicProxyAuth(NullProxyAuth):
|
class BasicAuth(NullProxyAuth):
|
||||||
CHALLENGE_HEADER = 'Proxy-Authenticate'
|
CHALLENGE_HEADER = None
|
||||||
AUTH_HEADER = 'Proxy-Authorization'
|
AUTH_HEADER = None
|
||||||
|
|
||||||
def __init__(self, password_manager, realm):
|
def __init__(self, password_manager, realm):
|
||||||
NullProxyAuth.__init__(self, password_manager)
|
NullProxyAuth.__init__(self, password_manager)
|
||||||
@ -80,6 +80,16 @@ class BasicProxyAuth(NullProxyAuth):
|
|||||||
return {self.CHALLENGE_HEADER: 'Basic realm="%s"' % self.realm}
|
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):
|
class PassMan(object):
|
||||||
|
|
||||||
def test(self, username_, password_token_):
|
def test(self, username_, password_token_):
|
||||||
|
@ -313,6 +313,22 @@ class TestHTTPAuth(tservers.HTTPProxyTest):
|
|||||||
assert ret.status_code == 202
|
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):
|
class TestHTTPS(tservers.HTTPProxyTest, CommonMixin, TcpMixin):
|
||||||
ssl = True
|
ssl = True
|
||||||
ssloptions = pathod.SSLOptions(request_client_cert=True)
|
ssloptions = pathod.SSLOptions(request_client_cert=True)
|
||||||
|
Loading…
Reference in New Issue
Block a user