Repository: italia/spid-cie-oidc-django (language: python)

Issue:
Trust mark validation endpoint issues
When validating the trust marks, the `trust_mark_status` endpoint of the trust anchor is only supporting POST requests and needs a django CSRF protection token to be processed, is this intended?
For example, in the [spid-cie-oidc-docs](https://docs.italia.it/italia/spid/spid-cie-oidc-docs/it/versione-corrente/esempi.html#en-5-trust-mark-status-request) the example of the trust mark status request doesn't include any CSRF protection header.

In [openid-federation](https://openid.net/specs/openid-federation-1_0.html#name-trust-mark-status-request) the trust mark status request must be made using a GET method when client authentication is not used. Will this GET method alternative be available?


Discussion / hints:
According to the federation specs, the trust marks status endpoint doesn't require CSRF protection

we can enable GET Method with a PR

This has produced a regression in the italian specs:
https://bitbucket.org/openid/connect/pull-requests/699#Lopenid-federation-1_0.xmlF3625T3643


please give me a week to resolve this before our final decision of this issue
I can try to write the GET method and make a PR if needed.

Fix patch:
diff --git a/spid_cie_oidc/authority/views.py b/spid_cie_oidc/authority/views.py
index eb4f3bb1..c2d6bec4 100644
--- a/spid_cie_oidc/authority/views.py
+++ b/spid_cie_oidc/authority/views.py
@@ -8,9 +8,11 @@
 from django.http import (
     Http404,
     HttpResponse,
-    JsonResponse
+    JsonResponse,
+    QueryDict
 )
 from django.urls import reverse
+from django.views.decorators.csrf import csrf_exempt
 
 from spid_cie_oidc.authority.models import (
     FederationDescendant,
@@ -199,7 +201,7 @@ def advanced_entity_listing(request):
 
 
 @schema(
-    methods=['GET'],
+    methods=['GET', 'POST'],
     get_request_schema = {
         "application/x-www-form-urlencoded": TrustMarkRequest
     },
@@ -210,20 +212,28 @@ def advanced_entity_listing(request):
     },
     tags = ['Federation API']
 )
+@csrf_exempt
 def trust_mark_status(request):
     failed_data = {"active": False}
-    if request.POST.get("sub", "") and request.POST.get("id", ""):
-        sub = request.POST["sub"]
-        _id = request.POST["id"]
 
-    elif request.POST.get("trust_mark", ""):
+    sub = request.POST.get("sub") or request.GET.get("sub", None)
+    _id = request.POST.get("trust_mark_id") or request.GET.get("trust_mark_id", None) \
+        or request.POST.get("id") or request.GET.get("id", None)
+    trust_mark = request.POST.get("trust_mark") or request.GET.get("trust_mark", None)
+
+    if request.method not in ['GET', 'POST']:
+        return JsonResponse({"error": "Method not allowed"}, status=400)
+
+    if trust_mark:
         try:
-            unpad_jwt_head(request.POST["trust_mark"])
-            payload = unpad_jwt_payload(request.POST["trust_mark"])
-            sub = payload.get("sub", "")
-            _id = payload.get("id", "")
+            unpad_jwt_head(trust_mark)
+            payload = unpad_jwt_payload(trust_mark)
+            sub = payload["sub"]
+            _id = payload["id"]
         except Exception:
             return JsonResponse(failed_data)
+    elif sub and _id:
+        pass
     else:
         return JsonResponse(failed_data)
 


Test patch:
diff --git a/spid_cie_oidc/authority/tests/test_02_trust_anchor_intermediary.py b/spid_cie_oidc/authority/tests/test_02_trust_anchor_intermediary.py
index 2153c0a9..61ea1fe2 100644
--- a/spid_cie_oidc/authority/tests/test_02_trust_anchor_intermediary.py
+++ b/spid_cie_oidc/authority/tests/test_02_trust_anchor_intermediary.py
@@ -264,6 +264,17 @@ def test_resolve_endpoint(self, mocked):
     def test_trust_mark_status_endpoint(self):
         url = reverse("oidcfed_trust_mark_status")
 
+        c = Client()
+        res = c.post(
+            url,
+            data={
+                "trust_mark_id": self.rp_assigned_profile.profile.profile_id,
+                "sub": self.rp_assigned_profile.descendant.sub,
+            },
+        )
+        self.assertTrue(res.status_code == 200)
+        self.assertTrue(res.json() == {"active": True})
+
         c = Client()
         res = c.post(
             url,
@@ -275,6 +286,33 @@ def test_trust_mark_status_endpoint(self):
         self.assertTrue(res.status_code == 200)
         self.assertTrue(res.json() == {"active": True})
 
+        res = c.get(
+            url,
+            data={
+                "trust_mark_id": self.rp_assigned_profile.profile.profile_id,
+                "sub": self.rp_assigned_profile.descendant.sub,
+            }
+        )
+        self.assertTrue(res.status_code == 200)
+        self.assertTrue(res.json() == {"active": True})
+
+        res = c.get(
+            url,
+            data={
+                "id": self.rp_assigned_profile.profile.profile_id,
+                "sub": self.rp_assigned_profile.descendant.sub,
+            }
+        )
+        self.assertTrue(res.status_code == 200)
+        self.assertTrue(res.json() == {"active": True})
+
+        res = c.get(
+            url,
+            data={}
+        )
+        self.assertTrue(res.status_code == 200)
+        self.assertTrue(res.json() == {"active": False})
+
         res = c.post(
             url,
             data={
@@ -293,6 +331,15 @@ def test_trust_mark_status_endpoint(self):
         self.assertTrue(res.status_code == 200)
         self.assertTrue(res.json() == {"active": False})
 
+        res = c.get(
+            url,
+            data={
+                "trust_mark_id": self.rp_assigned_profile.profile.profile_id,
+            },
+        )
+        self.assertTrue(res.status_code == 200)
+        self.assertTrue(res.json() == {"active": False})
+
         res = c.get(
             url,
             data={