diff --git a/api/config/settings/common.py b/api/config/settings/common.py index de1d653cb91fa3518273b8b103ed74fdee4b9259..f1a383c587b123c39a6cbf3dcd5ad0de445a30cf 100644 --- a/api/config/settings/common.py +++ b/api/config/settings/common.py @@ -377,6 +377,7 @@ REST_FRAMEWORK = { ), 'DEFAULT_AUTHENTICATION_CLASSES': ( 'funkwhale_api.common.authentication.JSONWebTokenAuthenticationQS', + 'funkwhale_api.common.authentication.BearerTokenHeaderAuth', 'rest_framework_jwt.authentication.JSONWebTokenAuthentication', 'rest_framework.authentication.SessionAuthentication', 'rest_framework.authentication.BasicAuthentication', diff --git a/api/funkwhale_api/common/auth.py b/api/funkwhale_api/common/auth.py index 75839b93662bfb0eb19a78d3b108c5c3690e5e5d..faf13571d6cd73208530a479ed92364989e304ad 100644 --- a/api/funkwhale_api/common/auth.py +++ b/api/funkwhale_api/common/auth.py @@ -29,9 +29,6 @@ class TokenHeaderAuth(BaseJSONWebTokenAuthentication): class TokenAuthMiddleware: - """ - Custom middleware (insecure) that takes user IDs from the query string. - """ def __init__(self, inner): # Store the ASGI application we were passed diff --git a/api/funkwhale_api/common/authentication.py b/api/funkwhale_api/common/authentication.py index b75f3b516d5d2505f40900f7314f1f70e557ecb2..c7566eac8bd0f3d5c115a3a5d6b16dd3aec5dd9e 100644 --- a/api/funkwhale_api/common/authentication.py +++ b/api/funkwhale_api/common/authentication.py @@ -1,3 +1,6 @@ +from django.utils.encoding import smart_text +from django.utils.translation import ugettext as _ + from rest_framework import exceptions from rest_framework_jwt import authentication from rest_framework_jwt.settings import api_settings @@ -18,3 +21,37 @@ class JSONWebTokenAuthenticationQS( def authenticate_header(self, request): return '{0} realm="{1}"'.format( api_settings.JWT_AUTH_HEADER_PREFIX, self.www_authenticate_realm) + + +class BearerTokenHeaderAuth( + authentication.BaseJSONWebTokenAuthentication): + """ + For backward compatibility purpose, we used Authorization: JWT <token> + but Authorization: Bearer <token> is probably better. + """ + www_authenticate_realm = 'api' + + def get_jwt_value(self, request): + auth = authentication.get_authorization_header(request).split() + auth_header_prefix = 'bearer' + + if not auth: + if api_settings.JWT_AUTH_COOKIE: + return request.COOKIES.get(api_settings.JWT_AUTH_COOKIE) + return None + + if smart_text(auth[0].lower()) != auth_header_prefix: + return None + + if len(auth) == 1: + msg = _('Invalid Authorization header. No credentials provided.') + raise exceptions.AuthenticationFailed(msg) + elif len(auth) > 2: + msg = _('Invalid Authorization header. Credentials string ' + 'should not contain spaces.') + raise exceptions.AuthenticationFailed(msg) + + return auth[1] + + def authenticate_header(self, request): + return '{0} realm="{1}"'.format('Bearer', self.www_authenticate_realm)