From a2fbcd9421dc798a5d2b826f99995f2f95ebbf56 Mon Sep 17 00:00:00 2001
From: Erwan Rouchet <rouchet@teklia.com>
Date: Tue, 7 Mar 2023 16:46:28 +0100
Subject: [PATCH] Add task authentication

---
 arkindex/ponos/authentication.py              | 36 ++++++++++++++++++-
 arkindex/project/settings.py                  |  1 +
 arkindex/project/tests/openapi/test_schema.py |  1 +
 3 files changed, 37 insertions(+), 1 deletion(-)

diff --git a/arkindex/ponos/authentication.py b/arkindex/ponos/authentication.py
index 8eaa6bf008..152619cb67 100644
--- a/arkindex/ponos/authentication.py
+++ b/arkindex/ponos/authentication.py
@@ -1,7 +1,9 @@
+from drf_spectacular.authentication import TokenScheme
 from drf_spectacular.contrib.rest_framework_simplejwt import SimpleJWTScheme
+from rest_framework.authentication import TokenAuthentication
 from rest_framework.exceptions import AuthenticationFailed
 
-from arkindex.ponos.models import Agent
+from arkindex.ponos.models import Agent, Task
 from rest_framework_simplejwt.authentication import JWTAuthentication
 from rest_framework_simplejwt.exceptions import InvalidToken
 from rest_framework_simplejwt.settings import api_settings
@@ -68,3 +70,35 @@ class AgentAuthenticationExtension(SimpleJWTScheme):
 
     target_class = "arkindex.ponos.authentication.AgentAuthentication"
     name = "agentAuth"
+
+
+class TaskAuthentication(TokenAuthentication):
+    keyword = 'Ponos'
+    model = Task
+
+    def authenticate_credentials(self, key):
+        try:
+            task = Task.objects.select_related('workflow__process__creator').get(token=key)
+        except Task.DoesNotExist:
+            # Same error message as the standard TokenAuthentication
+            raise AuthenticationFailed('Invalid token.')
+
+        if not task.workflow.process:
+            raise AuthenticationFailed('Task has no process.')
+
+        user = task.workflow.process.creator
+        if not user or not user.is_active:
+            # Same error message as the standard TokenAuthentication
+            raise AuthenticationFailed('User inactive or deleted.')
+
+        return (user, task)
+
+
+class TaskAuthenticationExtension(TokenScheme):
+    target_class = "arkindex.ponos.authentication.TaskAuthentication"
+    name = "taskAuth"
+    # The TokenScheme has a priority of -1 and matches both TokenAuthentication and its subclasses;
+    # we set the priority to a higher number to make this extension match first, and disable
+    # subclass matching so that this only applies to the TaskAuthentication.
+    priority = 0
+    match_subclasses = False
diff --git a/arkindex/project/settings.py b/arkindex/project/settings.py
index b5e354e42b..820a6c4de1 100644
--- a/arkindex/project/settings.py
+++ b/arkindex/project/settings.py
@@ -202,6 +202,7 @@ REST_FRAMEWORK = {
         'rest_framework.authentication.SessionAuthentication',
         'rest_framework.authentication.TokenAuthentication',
         'arkindex.ponos.authentication.AgentAuthentication',
+        'arkindex.ponos.authentication.TaskAuthentication',
     ),
     'DEFAULT_PAGINATION_CLASS': 'arkindex.project.pagination.PageNumberPagination',
     'DEFAULT_SCHEMA_CLASS': 'arkindex.project.openapi.AutoSchema',
diff --git a/arkindex/project/tests/openapi/test_schema.py b/arkindex/project/tests/openapi/test_schema.py
index 1dd19e06d2..ead901bae6 100644
--- a/arkindex/project/tests/openapi/test_schema.py
+++ b/arkindex/project/tests/openapi/test_schema.py
@@ -56,6 +56,7 @@ class TestAutoSchema(TestCase):
                     {'cookieAuth': []},
                     {'tokenAuth': []},
                     {'agentAuth': []},
+                    {'taskAuth': []},
                     # Allows no authentication too
                     {},
                 ],
-- 
GitLab