Merge pull request #1938 from SchrodingersGat/auth-bug

Fix bug when using token based auth
This commit is contained in:
Oliver 2021-08-10 23:24:01 +10:00 committed by GitHub
commit 1bf2a3e23f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -21,28 +21,15 @@ class AuthRequiredMiddleware(object):
assert hasattr(request, 'user') assert hasattr(request, 'user')
response = self.get_response(request) # API requests are handled by the DRF library
if request.path_info.startswith('/api/'):
return self.get_response(request)
if not request.user.is_authenticated: if not request.user.is_authenticated:
""" """
Normally, a web-based session would use csrftoken based authentication. Normally, a web-based session would use csrftoken based authentication.
However when running an external application (e.g. the InvenTree app), However when running an external application (e.g. the InvenTree app or Python library),
we wish to use token-based auth to grab media files. we must validate the user token manually.
So, we will allow token-based authentication but ONLY for the /media/ directory.
What problem is this solving?
- The InvenTree mobile app does not use csrf token auth
- Token auth is used by the Django REST framework, but that is under the /api/ endpoint
- Media files (e.g. Part images) are required to be served to the app
- We do not want to make /media/ files accessible without login!
There is PROBABLY a better way of going about this?
a) Allow token-based authentication against a user?
b) Serve /media/ files in a duplicate location e.g. /api/media/ ?
c) Is there a "standard" way of solving this problem?
My [google|stackoverflow]-fu has failed me. So this hack has been created.
""" """
authorized = False authorized = False
@ -56,20 +43,23 @@ class AuthRequiredMiddleware(object):
elif request.path_info.startswith('/accounts/'): elif request.path_info.startswith('/accounts/'):
authorized = True authorized = True
elif 'Authorization' in request.headers.keys(): elif 'Authorization' in request.headers.keys() or 'authorization' in request.headers.keys():
auth = request.headers['Authorization'].strip() auth = request.headers.get('Authorization', request.headers.get('authorization')).strip()
if auth.startswith('Token') and len(auth.split()) == 2: if auth.lower().startswith('token') and len(auth.split()) == 2:
token = auth.split()[1] token_key = auth.split()[1]
# Does the provided token match a valid user? # Does the provided token match a valid user?
if Token.objects.filter(key=token).exists(): try:
token = Token.objects.get(key=token_key)
allowed = ['/api/', '/media/'] # Provide the user information to the request
request.user = token.user
authorized = True
# Only allow token-auth for /media/ or /static/ dirs! except Token.DoesNotExist:
if any([request.path_info.startswith(a) for a in allowed]): logger.warning(f"Access denied for unknown token {token_key}")
authorized = True pass
# No authorization was found for the request # No authorization was found for the request
if not authorized: if not authorized:
@ -92,8 +82,7 @@ class AuthRequiredMiddleware(object):
return redirect('%s?next=%s' % (reverse_lazy('login'), request.path)) return redirect('%s?next=%s' % (reverse_lazy('login'), request.path))
# Code to be executed for each request/response after response = self.get_response(request)
# the view is called.
return response return response