From 7ef5c0058e4d3dfc43184e0313bd89aee0d55344 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 10 Aug 2021 22:50:49 +1000 Subject: [PATCH 1/2] Fix bug when using token based auth --- InvenTree/InvenTree/middleware.py | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/InvenTree/InvenTree/middleware.py b/InvenTree/InvenTree/middleware.py index b905e86795..e2fb3b7c43 100644 --- a/InvenTree/InvenTree/middleware.py +++ b/InvenTree/InvenTree/middleware.py @@ -21,8 +21,6 @@ class AuthRequiredMiddleware(object): assert hasattr(request, 'user') - response = self.get_response(request) - if not request.user.is_authenticated: """ Normally, a web-based session would use csrftoken based authentication. @@ -56,20 +54,22 @@ class AuthRequiredMiddleware(object): elif request.path_info.startswith('/accounts/'): authorized = True - elif 'Authorization' in request.headers.keys(): - auth = request.headers['Authorization'].strip() + elif 'Authorization' in request.headers.keys() or 'authorization' in request.headers.keys(): + auth = request.headers.get('Authorization', request.headers.get('authorization')).strip() if auth.startswith('Token') and len(auth.split()) == 2: token = auth.split()[1] # Does the provided token match a valid user? - if Token.objects.filter(key=token).exists(): + try: + token = Token.objects.get(key=token) - 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! - if any([request.path_info.startswith(a) for a in allowed]): - authorized = True + except Token.DoesNotExist: + pass # No authorization was found for the request if not authorized: @@ -92,8 +92,7 @@ class AuthRequiredMiddleware(object): return redirect('%s?next=%s' % (reverse_lazy('login'), request.path)) - # Code to be executed for each request/response after - # the view is called. + response = self.get_response(request) return response From 799f17ef506827fefc23acdae733abf55be713e1 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 10 Aug 2021 23:09:54 +1000 Subject: [PATCH 2/2] Bypass custom token auth for /api/ endpoint --- InvenTree/InvenTree/middleware.py | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/InvenTree/InvenTree/middleware.py b/InvenTree/InvenTree/middleware.py index e2fb3b7c43..3cd5aa74f7 100644 --- a/InvenTree/InvenTree/middleware.py +++ b/InvenTree/InvenTree/middleware.py @@ -21,26 +21,15 @@ class AuthRequiredMiddleware(object): assert hasattr(request, 'user') + # 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: """ Normally, a web-based session would use csrftoken based authentication. - However when running an external application (e.g. the InvenTree app), - we wish to use token-based auth to grab media files. - - 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. + However when running an external application (e.g. the InvenTree app or Python library), + we must validate the user token manually. """ authorized = False @@ -57,18 +46,19 @@ class AuthRequiredMiddleware(object): elif 'Authorization' in request.headers.keys() or 'authorization' in request.headers.keys(): auth = request.headers.get('Authorization', request.headers.get('authorization')).strip() - if auth.startswith('Token') and len(auth.split()) == 2: - token = auth.split()[1] + if auth.lower().startswith('token') and len(auth.split()) == 2: + token_key = auth.split()[1] # Does the provided token match a valid user? try: - token = Token.objects.get(key=token) + token = Token.objects.get(key=token_key) # Provide the user information to the request request.user = token.user authorized = True except Token.DoesNotExist: + logger.warning(f"Access denied for unknown token {token_key}") pass # No authorization was found for the request