Repository: encode/django-rest-framework

Issue:
HTTP basic auth: incorrectly padded base64 string causes an unhandled exception
The problem is in `rest_framework.authentication.BasicAuthentication.authenticate`. The call to `base64.b64decode` does not catch `binascii.Error`, which can be raised by `binascii.a2b_base64`

This assumes we want to handle that error and not let it propagate up the stack. I can't think of any reason not to, specially considering the raised exception message:

> Invalid basic header. Credentials not correctly base64 encoded.
## Stacktrace

```
Traceback (most recent call last):
  File "/app/.heroku/python/lib/python3.4/site-packages/django/core/handlers/base.py", line 149, in get_response
    response = self.process_exception_by_middleware(e, request)
  File "/app/.heroku/python/lib/python3.4/site-packages/django/core/handlers/base.py", line 147, in get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/app/.heroku/python/lib/python3.4/site-packages/django/views/decorators/csrf.py", line 58, in wrapped_view
    return view_func(*args, **kwargs)
  File "/app/.heroku/python/lib/python3.4/site-packages/django/views/generic/base.py", line 68, in view
    return self.dispatch(request, *args, **kwargs)
  File "/app/.heroku/python/lib/python3.4/site-packages/rest_framework/views.py", line 466, in dispatch
    response = self.handle_exception(exc)
  File "/app/.heroku/python/lib/python3.4/site-packages/rest_framework/views.py", line 454, in dispatch
    self.initial(request, *args, **kwargs)
  File "/app/.heroku/python/lib/python3.4/site-packages/rest_framework/views.py", line 376, in initial
    self.perform_authentication(request)
  File "/app/.heroku/python/lib/python3.4/site-packages/rest_framework/views.py", line 310, in perform_authentication
    request.user
  File "/app/.heroku/python/lib/python3.4/site-packages/rest_framework/request.py", line 353, in __getattribute__
    return super(Request, self).__getattribute__(attr)
  File "/app/.heroku/python/lib/python3.4/site-packages/rest_framework/request.py", line 193, in user
    self._authenticate()
  File "/app/.heroku/python/lib/python3.4/site-packages/rest_framework/request.py", line 316, in _authenticate
    user_auth_tuple = authenticator.authenticate(self)
  File "/app/.heroku/python/lib/python3.4/site-packages/rest_framework/authentication.py", line 78, in authenticate
    auth_parts = base64.b64decode(auth[1]).decode(HTTP_HEADER_ENCODING).partition(':')
  File "/app/.heroku/python/lib/python3.4/base64.py", line 90, in b64decode
    return binascii.a2b_base64(s)
binascii.Error: Incorrect padding
```
## Checklist
- [x] I have verified that that issue exists against the `master` branch of Django REST framework.
- [x] I have searched for similar issues in both open and closed tickets and cannot find a duplicate.
- [x] This is not a usage question. (Those should be directed to the [discussion group](https://groups.google.com/forum/#!forum/django-rest-framework) instead.)
- [x] This cannot be dealt with as a third party library. (We prefer new functionality to be [in the form of third party libraries](http://www.django-rest-framework.org/topics/third-party-resources/#about-third-party-packages) where possible.)
- [x] I have reduced the issue to the simplest possible case.
- [x] I have included a failing test as a pull request. (If you are unable to do so we can still accept the issue.)



Discussion:

Resolving patch:
diff --git a/rest_framework/authentication.py b/rest_framework/authentication.py
--- a/rest_framework/authentication.py
+++ b/rest_framework/authentication.py
@@ -4,6 +4,7 @@
 from __future__ import unicode_literals
 
 import base64
+import binascii
 
 from django.contrib.auth import authenticate, get_user_model
 from django.middleware.csrf import CsrfViewMiddleware
@@ -77,7 +78,7 @@ def authenticate(self, request):
 
         try:
             auth_parts = base64.b64decode(auth[1]).decode(HTTP_HEADER_ENCODING).partition(':')
-        except (TypeError, UnicodeDecodeError):
+        except (TypeError, UnicodeDecodeError, binascii.Error):
             msg = _('Invalid basic header. Credentials not correctly base64 encoded.')
             raise exceptions.AuthenticationFailed(msg)
 


Test patch:
diff --git a/tests/test_authentication.py b/tests/test_authentication.py
--- a/tests/test_authentication.py
+++ b/tests/test_authentication.py
@@ -85,6 +85,14 @@ def test_post_json_passing_basic_auth(self):
         response = self.csrf_client.post('/basic/', {'example': 'example'}, format='json', HTTP_AUTHORIZATION=auth)
         self.assertEqual(response.status_code, status.HTTP_200_OK)
 
+    def test_regression_handle_bad_base64_basic_auth_header(self):
+        """Ensure POSTing JSON over basic auth with incorrectly padded Base64 string is handled correctly"""
+        # regression test for issue in 'rest_framework.authentication.BasicAuthentication.authenticate'
+        # https://github.com/tomchristie/django-rest-framework/issues/4089
+        auth = 'Basic =a='
+        response = self.csrf_client.post('/basic/', {'example': 'example'}, format='json', HTTP_AUTHORIZATION=auth)
+        self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
+
     def test_post_form_failing_basic_auth(self):
         """Ensure POSTing form over basic auth without correct credentials fails"""
         response = self.csrf_client.post('/basic/', {'example': 'example'})