From 48a2c7cf4cd6d6ab0707265de071c50a78aada59 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Fri, 17 Apr 2026 10:23:54 +0200 Subject: [PATCH] Enhance API key authentication to support 'ApiKey ' prefix for compatibility with CrewNerd standard; added corresponding test case. --- rowers/authentication.py | 14 +++++++++++--- rowers/tests/test_api.py | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/rowers/authentication.py b/rowers/authentication.py index e5cf818e..05ced587 100644 --- a/rowers/authentication.py +++ b/rowers/authentication.py @@ -4,11 +4,19 @@ from rowers.models import APIKey class APIKeyAuthentication(BaseAuthentication): def authenticate(self, request): - api_key = request.META.get('HTTP_AUTHORIZATION') - if not api_key: + auth_header = request.META.get('HTTP_AUTHORIZATION') + if not auth_header: return None + + # Handle "ApiKey " format (CrewNerd standard) + if auth_header.startswith('ApiKey '): + api_key_value = auth_header[7:] # Strip "ApiKey " prefix + else: + # Support raw key for backward compatibility + api_key_value = auth_header + try: - api_key = APIKey.objects.get(key=api_key, is_active=True) + api_key = APIKey.objects.get(key=api_key_value, is_active=True) except APIKey.DoesNotExist: raise AuthenticationFailed('Invalid API key') diff --git a/rowers/tests/test_api.py b/rowers/tests/test_api.py index 6a460a81..c9bb4e84 100644 --- a/rowers/tests/test_api.py +++ b/rowers/tests/test_api.py @@ -718,6 +718,38 @@ class OwnApi(TestCase): self.assertEqual(response.status_code, 201) + def test_strokedataform_rowingdata_apikey_with_prefix(self): + """Test API key authentication with 'ApiKey ' prefix (CrewNerd format)""" + url = reverse('strokedata_rowingdata_apikey') + + filename = 'rowers/tests/testdata/testdata.csv' + f = open(filename, 'rb') + + # Use API Key header with "ApiKey " prefix (CrewNerd standard) + headers = { + "HTTP_AUTHORIZATION": f"ApiKey {self.apikey.key}", + } + + form_data = { + "workouttype": "rower", + "boattype": "1x", + "notes": "A test file upload with ApiKey prefix", + } + + # Send POST request + response = self.client.post( + url, + {"file": f, **form_data}, + format="multipart", + **headers, + ) + + f.close() + + # Assertions + self.assertEqual(response.status_code, 201) + + def test_strokedataform_empty(self): login = self.c.login(username=self.u.username, password=self.password)