Repository: abhinavsingh/proxy.py
Pull request #451 (2020-10-13 15:19:57)

Relax proxy auth requirement to allow mixed case for the auth type
Now "basic", "Basic", "BaSiC" are all allowed as auth type.  This allows for typos without compromising the authentication workflow.  See https://github.com/Anorov/PySocks/pull/147 for some background and https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Proxy-Authorization as reference to specification.

/cc @amirasaran

codecov[bot]: # [Codecov](https://codecov.io/gh/abhinavsingh/proxy.py/pull/451?src=pr&el=h1) Report
> Merging [#451](https://codecov.io/gh/abhinavsingh/proxy.py/pull/451?src=pr&el=desc) into [develop](https://codecov.io/gh/abhinavsingh/proxy.py/commit/969990464c4223b044e68daecf511d3f55b37d1a?el=desc) will **decrease** coverage by `0.01%`.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/abhinavsingh/proxy.py/pull/451/graphs/tree.svg?width=650&height=150&src=pr&token=Zh9J7b4la2)](https://codecov.io/gh/abhinavsingh/proxy.py/pull/451?src=pr&el=tree)

```diff
@@             Coverage Diff             @@
##           develop     #451      +/-   ##
===========================================
- Coverage    81.31%   81.29%   -0.02%     
===========================================
  Files           80       80              
  Lines         2991     2994       +3     
===========================================
+ Hits          2432     2434       +2     
- Misses         559      560       +1     
```


| [Impacted Files](https://codecov.io/gh/abhinavsingh/proxy.py/pull/451?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [proxy/http/proxy/server.py](https://codecov.io/gh/abhinavsingh/proxy.py/pull/451/diff?src=pr&el=tree#diff-cHJveHkvaHR0cC9wcm94eS9zZXJ2ZXIucHk=) | `77.85% <100.00%> (-0.12%)` | :arrow_down: |
| [proxy/proxy.py](https://codecov.io/gh/abhinavsingh/proxy.py/pull/451/diff?src=pr&el=tree#diff-cHJveHkvcHJveHkucHk=) | `93.75% <100.00%> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/abhinavsingh/proxy.py/pull/451?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/abhinavsingh/proxy.py/pull/451?src=pr&el=footer). Last update [9699904...5f5f6dd](https://codecov.io/gh/abhinavsingh/proxy.py/pull/451?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/proxy/http/proxy/server.py b/proxy/http/proxy/server.py
index d0297ea..168de7e 100644
--- a/proxy/http/proxy/server.py
+++ b/proxy/http/proxy/server.py
@@ -535,8 +535,10 @@ class HttpProxyPlugin(HttpProtocolHandlerPlugin):
 
     def authenticate(self) -> None:
         if self.flags.auth_code:
-            if b'proxy-authorization' not in self.request.headers or \
-                    self.request.headers[b'proxy-authorization'][1] != self.flags.auth_code:
+            if b'proxy-authorization' not in self.request.headers:
+                raise ProxyAuthenticationFailed()
+            parts = self.request.headers[b'proxy-authorization'][1].split()
+            if len(parts) != 2 and parts[0].lower() != b'basic' and parts[1] != self.flags.auth_code:
                 raise ProxyAuthenticationFailed()
 
     def connect_upstream(self) -> None:
diff --git a/proxy/proxy.py b/proxy/proxy.py
index 996cccb..c97646a 100644
--- a/proxy/proxy.py
+++ b/proxy/proxy.py
@@ -203,7 +203,7 @@ class Proxy:
         # Generate auth_code required for basic authentication if enabled
         auth_code = None
         if args.basic_auth:
-            auth_code = b'Basic %s' % base64.b64encode(bytes_(args.basic_auth))
+            auth_code = base64.b64encode(bytes_(args.basic_auth))
 
         return Flags(
             plugins=plugins,


Test patch:
diff --git a/tests/http/test_protocol_handler.py b/tests/http/test_protocol_handler.py
index 8b7b329..75f3c54 100644
--- a/tests/http/test_protocol_handler.py
+++ b/tests/http/test_protocol_handler.py
@@ -174,8 +174,7 @@ class TestHttpProtocolHandler(unittest.TestCase):
         self._conn = mock_fromfd.return_value
         self.mock_selector_for_client_read(mock_selector)
         flags = Flags(
-            auth_code=b'Basic %s' %
-                      base64.b64encode(b'user:pass'))
+            auth_code=base64.b64encode(b'user:pass'))
         flags.plugins = Proxy.load_plugins([
             b'proxy.http.proxy.HttpProxyPlugin',
             b'proxy.http.server.HttpWebServerPlugin',
@@ -208,8 +207,7 @@ class TestHttpProtocolHandler(unittest.TestCase):
         server.buffer_size.return_value = 0
 
         flags = Flags(
-            auth_code=b'Basic %s' %
-                      base64.b64encode(b'user:pass'))
+            auth_code=base64.b64encode(b'user:pass'))
         flags.plugins = Proxy.load_plugins([
             b'proxy.http.proxy.HttpProxyPlugin',
             b'proxy.http.server.HttpWebServerPlugin',
@@ -258,8 +256,7 @@ class TestHttpProtocolHandler(unittest.TestCase):
             mock_selector, server)
 
         flags = Flags(
-            auth_code=b'Basic %s' %
-                      base64.b64encode(b'user:pass'))
+            auth_code=base64.b64encode(b'user:pass'))
         flags.plugins = Proxy.load_plugins([
             b'proxy.http.proxy.HttpProxyPlugin',
             b'proxy.http.server.HttpWebServerPlugin'
diff --git a/tests/test_main.py b/tests/test_main.py
index b9b5651..1f0d7eb 100644
--- a/tests/test_main.py
+++ b/tests/test_main.py
@@ -138,7 +138,7 @@ class TestMain(unittest.TestCase):
         mock_acceptor_pool.assert_called_once()
         self.assertEqual(
             flgs.auth_code,
-            b'Basic dXNlcjpwYXNz')
+            b'dXNlcjpwYXNz')
 
     @mock.patch('time.sleep')
     @mock.patch('builtins.print')