From 947671391112f756dd168705f0dc707381f9bb6f Mon Sep 17 00:00:00 2001 From: mpeltriaux Date: Thu, 17 Aug 2023 10:44:58 +0200 Subject: [PATCH] Unit test api * adds unit test for APIUserToken * enhances handling of token fetching for API --- api/models/token.py | 6 +-- api/tests/unit/__init__.py | 7 ++++ api/tests/unit/test_token.py | 71 ++++++++++++++++++++++++++++++++++++ api/views/views.py | 8 +++- 4 files changed, 87 insertions(+), 5 deletions(-) create mode 100644 api/tests/unit/__init__.py create mode 100644 api/tests/unit/test_token.py diff --git a/api/models/token.py b/api/models/token.py index e0ad664..c528528 100644 --- a/api/models/token.py +++ b/api/models/token.py @@ -14,7 +14,7 @@ class APIUserToken(models.Model): valid_until = models.DateField( blank=True, null=True, - help_text="Token is only valid until this date", + help_text="Token is only valid until this date. Forever if null/blank.", ) is_active = models.BooleanField( default=False, @@ -25,12 +25,11 @@ class APIUserToken(models.Model): return self.token @staticmethod - def get_user_from_token(token: str, username: str): + def get_user_from_token(token: str): """ Getter for the related user object Args: token (str): The used token - username (str): The username Returns: user (User): Otherwise None @@ -39,7 +38,6 @@ class APIUserToken(models.Model): try: token_obj = APIUserToken.objects.get( token=token, - user__username=username ) if not token_obj.is_active: raise PermissionError("Token unverified") diff --git a/api/tests/unit/__init__.py b/api/tests/unit/__init__.py new file mode 100644 index 0000000..5be1b4a --- /dev/null +++ b/api/tests/unit/__init__.py @@ -0,0 +1,7 @@ +""" +Author: Michel Peltriaux +Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany +Contact: ksp-servicestelle@sgdnord.rlp.de +Created on: 17.08.23 + +""" diff --git a/api/tests/unit/test_token.py b/api/tests/unit/test_token.py new file mode 100644 index 0000000..0cdd9f8 --- /dev/null +++ b/api/tests/unit/test_token.py @@ -0,0 +1,71 @@ +""" +Author: Michel Peltriaux +Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany +Contact: ksp-servicestelle@sgdnord.rlp.de +Created on: 17.08.23 + +""" +from datetime import timedelta + +from django.utils.timezone import now + +from api.models import APIUserToken +from konova.tests.test_views import BaseTestCase + + +class APIUserTokenTestCase(BaseTestCase): + def setUp(self) -> None: + super().setUp() + + self.token = APIUserToken.objects.create() + self.superuser.api_token = self.token + self.superuser.save() + + def test_str(self): + self.assertEqual(str(self.token), self.token.token) + + def test_get_user_from_token(self): + a_day = timedelta(days=1) + today = now().date() + + self.assertFalse(self.token.is_active) + self.assertIsNone(self.token.valid_until) + + try: + #Token not existing --> fail + token_user = APIUserToken.get_user_from_token(self.token.token[::-1]) + self.fail("There should not have been any token") + except PermissionError: + pass + + try: + # Token not active --> fail + token_user = APIUserToken.get_user_from_token(self.token.token) + self.fail("Token is unverified but token user has been fetchable.") + except PermissionError: + pass + self.token.is_active = True + self.token.valid_until = today - a_day + self.token.save() + + try: + # Token valid until yesterday --> fail + token_user = APIUserToken.get_user_from_token(self.token.token) + self.fail("Token reached end of lifetime but token user has been fetchable.") + except PermissionError: + pass + + # Token valid until tomorrow --> success + self.token.valid_until = today + a_day + self.token.save() + + token_user = APIUserToken.get_user_from_token(self.token.token) + self.assertEqual(token_user, self.superuser) + del token_user + + # Token valid forever --> success + self.token.valid_until = None + self.token.save() + token_user = APIUserToken.get_user_from_token(self.token.token) + self.assertEqual(token_user, self.superuser) + diff --git a/api/views/views.py b/api/views/views.py index 75d764e..f3a86bc 100644 --- a/api/views/views.py +++ b/api/views/views.py @@ -53,7 +53,13 @@ class AbstractAPIView(View): # Fetch the proper user from the given request header token ksp_token = request.headers.get(KSP_TOKEN_HEADER_IDENTIFIER, None) ksp_user = request.headers.get(KSP_USER_HEADER_IDENTIFIER, None) - self.user = APIUserToken.get_user_from_token(ksp_token, ksp_user) + token_user = APIUserToken.get_user_from_token(ksp_token) + + if ksp_user != token_user.username: + raise PermissionError(f"Invalid token for {ksp_user}") + else: + self.user = token_user + request.user = self.user if not self.user.is_default_user(): raise PermissionError("Default permissions required")