🔥(back) remove collaboration-auth endpoint

We don't need anymore the collaboration-auth endpoint. Every code
related to it is removed.
This commit is contained in:
Manuel Raynaud
2025-03-25 15:04:47 +01:00
parent e86919fb9a
commit 8bee476b5b
5 changed files with 3 additions and 242 deletions

View File

@@ -380,10 +380,7 @@ class DocumentViewSet(
9. **Media Auth**: Authorize access to document media.
Example: GET /documents/media-auth/
10. **Collaboration Auth**: Authorize access to the collaboration server for a document.
Example: GET /documents/collaboration-auth/
11. **AI Transform**: Apply a transformation action on a piece of text with AI.
10. **AI Transform**: Apply a transformation action on a piece of text with AI.
Example: POST /documents/{id}/ai-transform/
Expected data:
- text (str): The input text.
@@ -391,7 +388,7 @@ class DocumentViewSet(
Returns: JSON response with the processed text.
Throttled by: AIDocumentRateThrottle, AIUserRateThrottle.
12. **AI Translate**: Translate a piece of text with AI.
11. **AI Translate**: Translate a piece of text with AI.
Example: POST /documents/{id}/ai-translate/
Expected data:
- text (str): The input text.
@@ -1207,17 +1204,6 @@ class DocumentViewSet(
logger.debug("Failed to extract parameters from subrequest URL: %s", exc)
raise drf.exceptions.PermissionDenied() from exc
def _auth_get_document(self, pk):
"""
Retrieves the document corresponding to the given primary key (pk).
Raises PermissionDenied if the document is not found.
"""
try:
return models.Document.objects.get(pk=pk)
except models.Document.DoesNotExist as exc:
logger.debug("Document with ID '%s' does not exist", pk)
raise drf.exceptions.PermissionDenied() from exc
@drf.decorators.action(detail=False, methods=["get"], url_path="media-auth")
def media_auth(self, request, *args, **kwargs):
"""
@@ -1265,42 +1251,6 @@ class DocumentViewSet(
return drf.response.Response("authorized", headers=request.headers, status=200)
@drf.decorators.action(detail=False, methods=["get"], url_path="collaboration-auth")
def collaboration_auth(self, request, *args, **kwargs):
"""
This view is used by an Nginx subrequest to control access to a document's
collaboration server.
"""
parsed_url = self._auth_get_original_url(request)
url_params = self._auth_get_url_params(
enums.COLLABORATION_WS_URL_PATTERN, parsed_url.query
)
document = self._auth_get_document(url_params["pk"])
abilities = document.get_abilities(request.user)
if not abilities.get(self.action, False):
logger.debug(
"User '%s' lacks permission for document '%s'",
request.user,
document.pk,
)
raise drf.exceptions.PermissionDenied()
if not settings.COLLABORATION_SERVER_SECRET:
logger.debug("Collaboration server secret is not defined")
raise drf.exceptions.PermissionDenied()
# Add the collaboration server secret token to the headers
headers = {
"Authorization": settings.COLLABORATION_SERVER_SECRET,
"X-Can-Edit": str(abilities["partial_update"]),
}
if request.user.is_authenticated:
headers["X-User-Id"] = str(request.user.id)
return drf.response.Response("authorized", headers=headers, status=200)
@drf.decorators.action(
detail=True,
methods=["post"],

View File

@@ -20,7 +20,6 @@ MEDIA_STORAGE_URL_PATTERN = re.compile(
MEDIA_STORAGE_URL_EXTRACT = re.compile(
f"{settings.MEDIA_URL:s}({UUID_REGEX}/{ATTACHMENTS_FOLDER}/{UUID_REGEX}{FILE_EXT_REGEX})"
)
COLLABORATION_WS_URL_PATTERN = re.compile(rf"(?:^|&)room=(?P<pk>{UUID_REGEX})(?:&|$)")
# In Django's code base, `LANGUAGES` is set by default with all supported languages.

View File

@@ -1,185 +0,0 @@
"""
Test collaboration websocket access API endpoint for users in impress's core app.
"""
from uuid import uuid4
from django.test import override_settings
import pytest
from rest_framework.test import APIClient
from core import factories, models
from core.tests.conftest import TEAM, USER, VIA
pytestmark = pytest.mark.django_db
def test_api_documents_collaboration_auth_unkown_document():
"""
Trying to connect to the collaboration server on a document ID that does not exist
should not have the side effect to create it (no regression test).
"""
original_url = f"http://localhost/collaboration/ws/?room={uuid4()!s}"
response = APIClient().get(
"/api/v1.0/documents/collaboration-auth/", HTTP_X_ORIGINAL_URL=original_url
)
assert response.status_code == 403
assert models.Document.objects.exists() is False
def test_api_documents_collaboration_auth_original_url_not_matching():
"""
Trying to authenticate on the collaboration server with an invalid
original url should return a 403.
"""
document = factories.DocumentFactory(link_reach="public")
response = APIClient().get(
"/api/v1.0/documents/collaboration-auth/",
HTTP_X_ORIGINAL_URL=f"http://localhost/ws/?invalid={document.pk}",
)
assert response.status_code == 403
assert "Authorization" not in response
assert "X-Can-Edit" not in response
assert "X-User-Id" not in response
def test_api_documents_collaboration_auth_secret_not_defined(settings):
"""
Trying to authenticate on the collaboration server when the secret is not defined
should return a 403.
"""
settings.COLLABORATION_SERVER_SECRET = None
document = factories.DocumentFactory(link_reach="public")
response = APIClient().get(
"/api/v1.0/documents/collaboration-auth/",
HTTP_X_ORIGINAL_URL=f"http://localhost/ws/?room={document.pk}",
)
assert response.status_code == 403
assert "Authorization" not in response
assert "X-Can-Edit" not in response
assert "X-User-Id" not in response
@override_settings(COLLABORATION_SERVER_SECRET="123")
@pytest.mark.parametrize("reach", ["authenticated", "restricted"])
def test_api_documents_collaboration_auth_anonymous_authenticated_or_restricted(reach):
"""
Anonymous users should not be allowed to connect to the collaboration server for a document
with link reach set to authenticated or restricted.
"""
document = factories.DocumentFactory(link_reach=reach)
response = APIClient().get(
"/api/v1.0/documents/collaboration-auth/",
HTTP_X_ORIGINAL_URL=f"http://localhost/ws/?room={document.pk}",
)
assert response.status_code == 403
assert "Authorization" not in response
assert "X-Can-Edit" not in response
assert "X-User-Id" not in response
@override_settings(COLLABORATION_SERVER_SECRET="123")
def test_api_documents_collaboration_auth_anonymous_public():
"""
Anonymous users should be able to connect to the collaboration server for a public document.
"""
document = factories.DocumentFactory(link_reach="public")
response = APIClient().get(
"/api/v1.0/documents/collaboration-auth/",
HTTP_X_ORIGINAL_URL=f"http://localhost/ws/?room={document.pk}",
)
assert response.status_code == 200
assert response["Authorization"] == "123"
assert response["X-Can-Edit"] == str(document.link_role == "editor")
assert "X-User-Id" not in response
@override_settings(COLLABORATION_SERVER_SECRET="123")
@pytest.mark.parametrize("reach", ["public", "authenticated"])
def test_api_documents_collaboration_auth_authenticated_public_or_authenticated(reach):
"""
Authenticated users who are not related to a document should be able to connect to the
collaboration server if this document's link reach is set to public or authenticated.
"""
user = factories.UserFactory()
client = APIClient()
client.force_login(user)
document = factories.DocumentFactory(link_reach=reach)
response = client.get(
"/api/v1.0/documents/collaboration-auth/",
HTTP_X_ORIGINAL_URL=f"http://localhost/ws/?room={document.pk}",
)
assert response.status_code == 200
assert response["Authorization"] == "123"
assert response["X-Can-Edit"] == str(document.link_role == "editor")
assert response["X-User-Id"] == str(user.id)
@override_settings(COLLABORATION_SERVER_SECRET="123")
def test_api_documents_collaboration_auth_authenticated_restricted():
"""
Authenticated users who are not related to a document should not be allowed to connect to the
collaboration server if this document's link reach is set to restricted.
"""
user = factories.UserFactory()
client = APIClient()
client.force_login(user)
document = factories.DocumentFactory(link_reach="restricted")
response = client.get(
"/api/v1.0/documents/collaboration-auth/",
HTTP_X_ORIGINAL_URL=f"http://localhost/ws/?room={document.pk}",
)
assert response.status_code == 403
assert "Authorization" not in response
assert "X-Can-Edit" not in response
assert "X-User-Id" not in response
@override_settings(COLLABORATION_SERVER_SECRET="123")
@pytest.mark.parametrize("role", models.RoleChoices.values)
@pytest.mark.parametrize("via", VIA)
def test_api_documents_collaboration_auth_related(via, role, mock_user_teams):
"""
Users who have a specific access to a document, whatever the role, should be able to
connect to the collaboration server for this document.
"""
user = factories.UserFactory()
client = APIClient()
client.force_login(user)
document = factories.DocumentFactory(link_reach="restricted")
if via == USER:
factories.UserDocumentAccessFactory(document=document, user=user, role=role)
elif via == TEAM:
mock_user_teams.return_value = ["lasuite", "unknown"]
factories.TeamDocumentAccessFactory(
document=document, team="lasuite", role=role
)
response = client.get(
"/api/v1.0/documents/collaboration-auth/",
HTTP_X_ORIGINAL_URL=f"http://localhost/ws/?room={document.pk}",
)
assert response.status_code == 200
assert response["Authorization"] == "123"
assert response["X-Can-Edit"] == str(role != "reader")
assert response["X-User-Id"] == str(user.id)

View File

@@ -75,15 +75,11 @@ ingressCollaborationWS:
## @param ingressCollaborationWS.customBackends Add custom backends to ingress
customBackends: []
## @param ingressCollaborationWS.annotations.nginx.ingress.kubernetes.io/auth-response-headers
## @param ingressCollaborationWS.annotations.nginx.ingress.kubernetes.io/auth-url
## @param ingressCollaborationWS.annotations.nginx.ingress.kubernetes.io/enable-websocket
## @param ingressCollaborationWS.annotations.nginx.ingress.kubernetes.io/proxy-read-timeout
## @param ingressCollaborationWS.annotations.nginx.ingress.kubernetes.io/proxy-send-timeout
## @param ingressCollaborationWS.annotations.nginx.ingress.kubernetes.io/upstream-hash-by
annotations:
nginx.ingress.kubernetes.io/auth-response-headers: "Authorization, X-Can-Edit, X-User-Id"
nginx.ingress.kubernetes.io/auth-url: https://impress.example.com/api/v1.0/documents/collaboration-auth/
nginx.ingress.kubernetes.io/enable-websocket: "true"
nginx.ingress.kubernetes.io/proxy-read-timeout: "86400"
nginx.ingress.kubernetes.io/proxy-send-timeout: "86400"