diff options
author | Thomas Kriechbaumer <Kriechi@users.noreply.github.com> | 2016-08-16 10:07:59 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-08-16 10:07:59 +0200 |
commit | 17c65e46cbdcf328dff22acaf4de8704119678ff (patch) | |
tree | fe8ba75b97ab565c6549a3a60e2b9ce0a454da61 | |
parent | f9f0ac848e8a691a78d4458f3d25f21b3e943658 (diff) | |
parent | a9401472cd8002f6e35da8f180400a8b980fc22c (diff) | |
download | mitmproxy-17c65e46cbdcf328dff22acaf4de8704119678ff.tar.gz mitmproxy-17c65e46cbdcf328dff22acaf4de8704119678ff.tar.bz2 mitmproxy-17c65e46cbdcf328dff22acaf4de8704119678ff.zip |
Merge pull request #1480 from mhils/reverse-proxy-auth
Add basic auth support for reverse proxy mode
-rw-r--r-- | mitmproxy/protocol/http.py | 22 | ||||
-rw-r--r-- | mitmproxy/proxy/config.py | 14 | ||||
-rw-r--r-- | netlib/http/authentication.py | 16 | ||||
-rw-r--r-- | test/mitmproxy/test_server.py | 16 |
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) |