Skip to content

Commit

Permalink
Merge pull request #29 from GPP-Woo/feature/10-document-api-auth-and-…
Browse files Browse the repository at this point in the history
…permission

Document API authorization
  • Loading branch information
bart-maykin authored Feb 12, 2025
2 parents 1ad7293 + d4ee99b commit e35a923
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 3 deletions.
8 changes: 7 additions & 1 deletion src/woo_search/api/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ paths:
$ref: '#/components/schemas/Document'
required: true
security:
- {}
- tokenAuth: []
responses:
'202':
content:
Expand Down Expand Up @@ -123,6 +123,12 @@ components:
required:
- naam
- uuid
securitySchemes:
tokenAuth:
type: apiKey
in: header
name: Authorization
description: Token-based authentication with required prefix "Token"
externalDocs:
description: Functional and technical documentation
url: https://gpp-zoeken.readthedocs.io/
64 changes: 64 additions & 0 deletions src/woo_search/api/tests/mixin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
from rest_framework import status
from rest_framework.test import APIClient

from .factories import TokenAuthFactory


class APIKeyUnAuthorizedMixin:
client: APIClient

def assertWrongApiKeyProhibitsPostEndpointAccess(self, url):
no_permission_token = TokenAuthFactory.create(permissions=[]).token
read_token = TokenAuthFactory.create(read_permission=True).token

with self.subTest( # pyright: ignore[reportAttributeAccessIssue]
"no token given"
):
response = self.client.post(url)
self.assertEqual( # pyright: ignore[reportAttributeAccessIssue]
response.status_code, status.HTTP_401_UNAUTHORIZED
)

with self.subTest( # pyright: ignore[reportAttributeAccessIssue]
"none existing token"
):
response = self.client.post(url, headers={"Authorization": "Token broken"})
self.assertEqual( # pyright: ignore[reportAttributeAccessIssue]
response.status_code, status.HTTP_401_UNAUTHORIZED
)

with self.subTest( # pyright: ignore[reportAttributeAccessIssue]
"token with no permission"
):
response = self.client.post(
url,
headers={"Authorization": f"Token {no_permission_token}"},
)
self.assertEqual( # pyright: ignore[reportAttributeAccessIssue]
response.status_code, status.HTTP_403_FORBIDDEN
)

with self.subTest( # pyright: ignore[reportAttributeAccessIssue]
"token with wrong permission"
):
response = self.client.post(
url, headers={"Authorization": f"Token {read_token}"}
)
self.assertEqual( # pyright: ignore[reportAttributeAccessIssue]
response.status_code, status.HTTP_403_FORBIDDEN
)


class TokenAuthMixin:
client: APIClient

@classmethod
def setUpTestData(cls):
super().setUpTestData() # pyright: ignore[reportAttributeAccessIssue]

cls.token_auth = TokenAuthFactory.create(read_write_permission=True)

def setUp(self):
super().setUp() # pyright: ignore[reportAttributeAccessIssue]

self.client.credentials(HTTP_AUTHORIZATION=f"Token {self.token_auth.token}")
6 changes: 6 additions & 0 deletions src/woo_search/conf/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,12 @@
REST_FRAMEWORK["DEFAULT_PAGINATION_CLASS"] = (
"rest_framework.pagination.PageNumberPagination"
)
REST_FRAMEWORK["DEFAULT_PERMISSION_CLASSES"] = (
"woo_search.api.permissions.TokenAuthPermission",
)
REST_FRAMEWORK["DEFAULT_AUTHENTICATION_CLASSES"] = (
"woo_search.api.authorization.TokenAuthentication",
)
REST_FRAMEWORK["EXCEPTION_HANDLER"] = "rest_framework.views.exception_handler"

SPECTACULAR_SETTINGS = {
Expand Down
12 changes: 10 additions & 2 deletions src/woo_search/search_index/tests/test_publications_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,22 @@
from rest_framework import status
from rest_framework.test import APITestCase

from woo_search.api.tests.mixin import APIKeyUnAuthorizedMixin, TokenAuthMixin
from woo_search.search_index.client import get_client
from woo_search.utils.tests.vcr import VCRMixin

from ..documents import Document
from .base import ElasticSearchAPITestCase


class DocumentAPITest(APITestCase):
class DocumentApiTest(APIKeyUnAuthorizedMixin, APITestCase):
def test_api_with_wrong_credentials_blocks_access(self):
url = reverse("api:document-list")

self.assertWrongApiKeyProhibitsPostEndpointAccess(url)


class DocumentAPITest(TokenAuthMixin, APITestCase):
url = reverse("api:document-list")

@patch("woo_search.search_index.tasks.publications.index_document.delay")
Expand Down Expand Up @@ -70,7 +78,7 @@ def test_document_api_with_errors_does_not_call_index_document_celery_task(
patched_index_document.assert_not_called()


class DocumentApiE2ETest(VCRMixin, ElasticSearchAPITestCase):
class DocumentApiE2ETest(TokenAuthMixin, VCRMixin, ElasticSearchAPITestCase):
@override_settings(CELERY_TASK_ALWAYS_EAGER=True)
def test_document_creation_happy_flow(self):
url = reverse("api:document-list")
Expand Down

0 comments on commit e35a923

Please sign in to comment.