diff --git a/hawc/apps/common/auth.py b/hawc/apps/common/auth.py new file mode 100644 index 0000000000..69ba871a69 --- /dev/null +++ b/hawc/apps/common/auth.py @@ -0,0 +1,28 @@ +from django.contrib.auth.backends import ModelBackend +from rest_framework.authentication import get_authorization_header +from rest_framework.authtoken.models import Token + + +class TokenBackend(ModelBackend): + keyword = "Token" + + def get_token_from_header(self, request) -> str: + auth = get_authorization_header(request).split() + token = "" + if auth and auth[0].lower() == self.keyword.lower().encode() and len(auth) == 2: + try: + token = auth[1].decode() + except UnicodeError: + pass + return token + + def authenticate(self, request, token=None, **kwargs): + if request is not None and token is None: + token = self.get_token_from_header(request) + if not token: + return None + try: + token_obj = Token.objects.select_related("user").get(key=token) + except Token.DoesNotExist: + return + return token_obj.user if self.user_can_authenticate(token_obj.user) else None diff --git a/hawc/apps/myuser/api.py b/hawc/apps/myuser/api.py index 46ef185ab3..d345a26f4d 100644 --- a/hawc/apps/myuser/api.py +++ b/hawc/apps/myuser/api.py @@ -1,3 +1,4 @@ +from django.contrib.auth import login from rest_framework.authtoken.views import ObtainAuthToken from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response @@ -25,4 +26,6 @@ class HawcValidateAuthToken(APIView): permission_classes = [IsAuthenticated] def get(self, request, format=None): + # create a django session for django view + login(request, request.user) return Response({"valid": True}) diff --git a/hawc/apps/myuser/models.py b/hawc/apps/myuser/models.py index 3970ad4c79..5a5ed1bb45 100644 --- a/hawc/apps/myuser/models.py +++ b/hawc/apps/myuser/models.py @@ -38,6 +38,7 @@ class HAWCUser(AbstractBaseUser, PermissionsMixin): USERNAME_FIELD = "email" CAN_CREATE_ASSESSMENTS = "can-create-assessments" + backend = "django.contrib.auth.backends.ModelBackend" class Meta: ordering = ("last_name",) diff --git a/hawc/main/settings/base.py b/hawc/main/settings/base.py index 5b759d80d6..410b0fcead 100644 --- a/hawc/main/settings/base.py +++ b/hawc/main/settings/base.py @@ -185,6 +185,10 @@ # Session and authentication AUTH_USER_MODEL = "myuser.HAWCUser" AUTH_PROVIDERS = {AuthProvider(p) for p in os.getenv("HAWC_AUTH_PROVIDERS", "django").split("|")} +AUTHENTICATION_BACKENDS = [ + "django.contrib.auth.backends.ModelBackend", + "hawc.apps.common.auth.TokenBackend", +] PASSWORD_RESET_TIMEOUT = 259200 # 3 days, in seconds SESSION_COOKIE_AGE = int(os.getenv("HAWC_SESSION_DURATION", "604800")) # 1 week SESSION_COOKIE_DOMAIN = os.getenv("HAWC_SESSION_COOKIE_DOMAIN", None) diff --git a/tests/client/test_client.py b/tests/client/test_client.py index ba2a881be3..95bcafc10c 100644 --- a/tests/client/test_client.py +++ b/tests/client/test_client.py @@ -47,11 +47,19 @@ def test_set_authentication_token(self): client.set_authentication_token("123") assert err.value.status_code == 403 + with pytest.raises(HawcClientException) as err: + client.session.get(f"{self.live_server_url}/assessment/1/") + assert err.value.status_code == 403 + user = HAWCUser.objects.get(email="pm@hawcproject.org") token = user.get_api_token().key resp = client.set_authentication_token(token) assert resp == {"valid": True} + # can also access regular Django views that are private + resp = client.session.get(f"{self.live_server_url}/assessment/1/") + assert resp.status_code == 200 + #################### # BaseClient tests # ####################