From 94dcfe338a52304f5895914ac59540b6176c679e Mon Sep 17 00:00:00 2001 From: zhengxie Date: Mon, 13 Apr 2015 11:59:57 +0800 Subject: [PATCH] [api2] Return 401 if api token is invalid --- seahub/api2/authentication.py | 32 +++++++++++++++++++++++--------- tests/api/test_auth.py | 17 +++++++++++++++-- 2 files changed, 38 insertions(+), 11 deletions(-) diff --git a/seahub/api2/authentication.py b/seahub/api2/authentication.py index 2779de541b..d884026d13 100644 --- a/seahub/api2/authentication.py +++ b/seahub/api2/authentication.py @@ -1,6 +1,8 @@ import datetime import logging +from rest_framework import status from rest_framework.authentication import BaseAuthentication +from rest_framework.exceptions import APIException import seaserv from seahub.base.accounts import User @@ -25,6 +27,14 @@ def within_ten_min(d1, d2): HEADER_CLIENT_VERSION = 'HTTP_SEAFILE_CLEINT_VERSION' HEADER_PLATFORM_VERSION = 'HTTP_SEAFILE_PLATFORM_VERSION' +class AuthenticationFailed(APIException): + status_code = status.HTTP_401_UNAUTHORIZED + default_detail = 'Incorrect authentication credentials.' + + def __init__(self, detail=None): + self.detail = detail or self.default_detail + + class TokenAuthentication(BaseAuthentication): """ Simple token based authentication. @@ -42,13 +52,17 @@ class TokenAuthentication(BaseAuthentication): def authenticate(self, request): auth = request.META.get('HTTP_AUTHORIZATION', '').split() - key = None - if len(auth) == 2 and auth[0].lower() == "token": - key = auth[1] - - if not key: + if not auth or auth[0].lower() != 'token': return None + if len(auth) == 1: + msg = 'Invalid token header. No credentials provided.' + raise AuthenticationFailed(msg) + elif len(auth) > 2: + msg = 'Invalid token header. Token string should not contain spaces.' + raise AuthenticationFailed(msg) + + key = auth[1] ret = self.authenticate_v2(request, key) if ret: return ret @@ -67,12 +81,12 @@ class TokenAuthentication(BaseAuthentication): try: token = Token.objects.get(key=key) except Token.DoesNotExist: - return None + raise AuthenticationFailed('Invalid token') try: user = User.objects.get(email=token.user) except User.DoesNotExist: - return None + raise AuthenticationFailed('User inactive or deleted') if MULTI_TENANCY: orgs = seaserv.get_orgs_by_user(token.user) @@ -88,12 +102,12 @@ class TokenAuthentication(BaseAuthentication): try: token = TokenV2.objects.get(key=key) except TokenV2.DoesNotExist: - return None + raise AuthenticationFailed('Invalid token') try: user = User.objects.get(email=token.user) except User.DoesNotExist: - return None + raise AuthenticationFailed('User inactive or deleted') if MULTI_TENANCY: orgs = seaserv.get_orgs_by_user(token.user) diff --git a/tests/api/test_auth.py b/tests/api/test_auth.py index 1e585d6914..2de0a0d86f 100644 --- a/tests/api/test_auth.py +++ b/tests/api/test_auth.py @@ -18,9 +18,22 @@ def fake_ccnet_id(): return randstring(length=40) class AuthTest(ApiTestBase): - """This tests involves creating/deleting api tokens, so for this test we use - a specific auth token so that it won't affect other test cases. + """This tests involves creating/deleting api tokens, so for this test we + use a specific auth token so that it won't affect other test cases. """ + def test_auth_token_missing(self): + return self.get(AUTH_PING_URL, token=None, use_token=False, + expected=403) + + def test_auth_token_is_empty(self): + return self.get(AUTH_PING_URL, token='', expected=401) + + def test_auth_token_contains_space(self): + return self.get(AUTH_PING_URL, token='token with space', expected=401) + + def test_random_auth_token(self): + return self.get(AUTH_PING_URL, token='randomtoken', expected=401) + def test_logout_device(self): token = self._desktop_login() self._do_auth_ping(token, expected=200)