♻️(backend) align CSRF token header with Django conventions

Update the CSRF header naming to follow Django standards,
avoiding duplicated client-side logic with inconsistent
header names.
This commit is contained in:
lebaudantoine
2026-04-29 11:07:13 +02:00
parent 6ee89b201e
commit 181b97b310
2 changed files with 17 additions and 17 deletions
+2 -2
View File
@@ -106,7 +106,7 @@ class SessionViewSet(viewsets.ViewSet):
"""Poll a session for its current state and, if terminal, consume it. """Poll a session for its current state and, if terminal, consume it.
Authenticates the caller using the addonsSid cookie (set by Authenticates the caller using the addonsSid cookie (set by
/init) together with the X-CSRF-Token header, which must match /init) together with the X-CSRFToken header, which must match
the CSRF token issued for that session. The session id alone is not the CSRF token issued for that session. The session id alone is not
sufficient — both must be presented and must correspond. sufficient — both must be presented and must correspond.
@@ -127,7 +127,7 @@ class SessionViewSet(viewsets.ViewSet):
""" """
session_id = request.COOKIES.get(settings.ADDONS_SESSION_ID_COOKIE) session_id = request.COOKIES.get(settings.ADDONS_SESSION_ID_COOKIE)
submitted_csrf = request.headers.get("X-CSRF-Token") submitted_csrf = request.headers.get("X-CSRFToken")
if not session_id: if not session_id:
return drf_response.Response( return drf_response.Response(
@@ -95,7 +95,7 @@ def test_init_cookie_authorizes_subsequent_poll():
poll_response = api_client.post( poll_response = api_client.post(
"/api/v1.0/addons/sessions/poll/", "/api/v1.0/addons/sessions/poll/",
HTTP_X_CSRF_TOKEN=csrf_token, HTTP_X_CSRFTOKEN=csrf_token,
) )
assert poll_response.status_code == 202 assert poll_response.status_code == 202
@@ -180,7 +180,7 @@ def test_poll_rejects_invalid_csrf_token():
poll_response = api_client.post( poll_response = api_client.post(
"/api/v1.0/addons/sessions/poll/", "/api/v1.0/addons/sessions/poll/",
HTTP_X_CSRF_TOKEN="invalid-csrf-token", HTTP_X_CSRFTOKEN="invalid-csrf-token",
) )
# SuspiciousOperation translates to 400 via Django's exception middleware. # SuspiciousOperation translates to 400 via Django's exception middleware.
@@ -202,7 +202,7 @@ def test_poll_session_not_found(mock_get_session_data):
poll_response = api_client.post( poll_response = api_client.post(
"/api/v1.0/addons/sessions/poll/", "/api/v1.0/addons/sessions/poll/",
HTTP_X_CSRF_TOKEN=csrf_token, HTTP_X_CSRFTOKEN=csrf_token,
) )
assert poll_response.status_code == 404 assert poll_response.status_code == 404
@@ -224,7 +224,7 @@ def test_poll_session_corrupted(mock_get_session_data):
poll_response = api_client.post( poll_response = api_client.post(
"/api/v1.0/addons/sessions/poll/", "/api/v1.0/addons/sessions/poll/",
HTTP_X_CSRF_TOKEN=csrf_token, HTTP_X_CSRFTOKEN=csrf_token,
) )
assert poll_response.status_code == 400 assert poll_response.status_code == 400
@@ -249,7 +249,7 @@ def test_poll_session_authenticated():
poll_response = api_client.post( poll_response = api_client.post(
"/api/v1.0/addons/sessions/poll/", "/api/v1.0/addons/sessions/poll/",
HTTP_X_CSRF_TOKEN=csrf_token, HTTP_X_CSRFTOKEN=csrf_token,
) )
assert poll_response.status_code == 200 assert poll_response.status_code == 200
@@ -271,7 +271,7 @@ def test_poll_session_authenticated():
# Server cleared the addonsSid cookie; APIClient drops it → no credentials. # Server cleared the addonsSid cookie; APIClient drops it → no credentials.
poll_response = api_client.post( poll_response = api_client.post(
"/api/v1.0/addons/sessions/poll/", "/api/v1.0/addons/sessions/poll/",
HTTP_X_CSRF_TOKEN=csrf_token, HTTP_X_CSRFTOKEN=csrf_token,
) )
assert poll_response.status_code == 401 assert poll_response.status_code == 401
@@ -279,7 +279,7 @@ def test_poll_session_authenticated():
api_client.cookies["addonsSid"] = session_id_cookie.value api_client.cookies["addonsSid"] = session_id_cookie.value
poll_response = api_client.post( poll_response = api_client.post(
"/api/v1.0/addons/sessions/poll/", "/api/v1.0/addons/sessions/poll/",
HTTP_X_CSRF_TOKEN=csrf_token, HTTP_X_CSRFTOKEN=csrf_token,
) )
assert poll_response.status_code == 404 assert poll_response.status_code == 404
assert poll_response.json() == {"detail": "Session not found."} assert poll_response.json() == {"detail": "Session not found."}
@@ -307,11 +307,11 @@ def test_poll_two_clients_do_not_interfere():
# Each client polls its own session. # Each client polls its own session.
poll_a = client_a.post( poll_a = client_a.post(
"/api/v1.0/addons/sessions/poll/", "/api/v1.0/addons/sessions/poll/",
HTTP_X_CSRF_TOKEN=csrf_a, HTTP_X_CSRFTOKEN=csrf_a,
) )
poll_b = client_b.post( poll_b = client_b.post(
"/api/v1.0/addons/sessions/poll/", "/api/v1.0/addons/sessions/poll/",
HTTP_X_CSRF_TOKEN=csrf_b, HTTP_X_CSRFTOKEN=csrf_b,
) )
assert poll_a.status_code == 202 assert poll_a.status_code == 202
assert poll_b.status_code == 202 assert poll_b.status_code == 202
@@ -319,7 +319,7 @@ def test_poll_two_clients_do_not_interfere():
# Cross-use (A's cookie + B's CSRF) must be rejected. # Cross-use (A's cookie + B's CSRF) must be rejected.
cross_response = client_a.post( cross_response = client_a.post(
"/api/v1.0/addons/sessions/poll/", "/api/v1.0/addons/sessions/poll/",
HTTP_X_CSRF_TOKEN=csrf_b, HTTP_X_CSRFTOKEN=csrf_b,
) )
assert cross_response.status_code == 400 assert cross_response.status_code == 400
@@ -336,13 +336,13 @@ def test_poll_two_clients_do_not_interfere():
): ):
poll_a = client_a.post( poll_a = client_a.post(
"/api/v1.0/addons/sessions/poll/", "/api/v1.0/addons/sessions/poll/",
HTTP_X_CSRF_TOKEN=csrf_a, HTTP_X_CSRFTOKEN=csrf_a,
) )
assert poll_a.status_code == 200 assert poll_a.status_code == 200
poll_b = client_b.post( poll_b = client_b.post(
"/api/v1.0/addons/sessions/poll/", "/api/v1.0/addons/sessions/poll/",
HTTP_X_CSRF_TOKEN=csrf_b, HTTP_X_CSRFTOKEN=csrf_b,
) )
assert poll_b.status_code == 202 assert poll_b.status_code == 202
@@ -369,14 +369,14 @@ def test_poll_csrf_attack_does_not_disrupt_legitimate_client():
# Fabricated CSRF token # Fabricated CSRF token
attack_bad_csrf = attacker.post( attack_bad_csrf = attacker.post(
"/api/v1.0/addons/sessions/poll/", "/api/v1.0/addons/sessions/poll/",
HTTP_X_CSRF_TOKEN="attacker-guessed-token", HTTP_X_CSRFTOKEN="attacker-guessed-token",
) )
assert attack_bad_csrf.status_code == 400 assert attack_bad_csrf.status_code == 400
# Legitimate client's session is still usable. # Legitimate client's session is still usable.
legitimate_poll = legitimate.post( legitimate_poll = legitimate.post(
"/api/v1.0/addons/sessions/poll/", "/api/v1.0/addons/sessions/poll/",
HTTP_X_CSRF_TOKEN=csrf_token, HTTP_X_CSRFTOKEN=csrf_token,
) )
assert legitimate_poll.status_code == 202 assert legitimate_poll.status_code == 202
assert legitimate_poll.json() == {"state": "pending"} assert legitimate_poll.json() == {"state": "pending"}
@@ -508,7 +508,7 @@ def test_exchange_success_enables_poll_to_complete():
# 3. Taskpane's next poll transitions from pending → authenticated. # 3. Taskpane's next poll transitions from pending → authenticated.
poll_response = taskpane.post( poll_response = taskpane.post(
"/api/v1.0/addons/sessions/poll/", "/api/v1.0/addons/sessions/poll/",
HTTP_X_CSRF_TOKEN=csrf_token, HTTP_X_CSRFTOKEN=csrf_token,
) )
assert poll_response.status_code == 200 assert poll_response.status_code == 200
response_data = poll_response.json() response_data = poll_response.json()