✅(backend) strengthen external API viewset test coverage
Reinforce the test suite around the external API viewset to better prevent regressions, permission leaks, and unexpected failures. Adds additional scenarios covering permission enforcement, edge cases, and error handling to ensure the external API behavior remains stable and secure as it evolves.
This commit is contained in:
committed by
aleb_the_flash
parent
ed5c1bbd84
commit
44d68a9c80
@@ -2,15 +2,18 @@
|
||||
Tests for external API /room endpoint
|
||||
"""
|
||||
|
||||
# pylint: disable=W0621
|
||||
# pylint: disable=W0621,C0302
|
||||
|
||||
import uuid
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from unittest import mock
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
import jwt
|
||||
import pytest
|
||||
import responses
|
||||
from lasuite.oidc_resource_server.authentication import ResourceServerAuthentication
|
||||
from rest_framework.test import APIClient
|
||||
|
||||
from core.factories import (
|
||||
@@ -53,6 +56,23 @@ def test_api_rooms_list_requires_authentication():
|
||||
assert response.status_code == 401
|
||||
|
||||
|
||||
def test_api_rooms_list_inactive_user(settings):
|
||||
"""List should return 401 if user is inactive."""
|
||||
settings.APPLICATION_JWT_SECRET_KEY = "devKey"
|
||||
|
||||
user1 = UserFactory(is_active=False)
|
||||
RoomFactory(users=[(user1, RoleChoices.OWNER)])
|
||||
|
||||
token = generate_test_token(user1, [ApplicationScope.ROOMS_LIST])
|
||||
|
||||
client = APIClient()
|
||||
client.credentials(HTTP_AUTHORIZATION=f"Bearer {token}")
|
||||
response = client.get("/external-api/v1.0/rooms/")
|
||||
|
||||
assert response.status_code == 401
|
||||
assert "user account is disabled" in str(response.data).lower()
|
||||
|
||||
|
||||
def test_api_rooms_list_with_valid_token(settings):
|
||||
"""Listing rooms with valid token should succeed."""
|
||||
|
||||
@@ -73,6 +93,24 @@ def test_api_rooms_list_with_valid_token(settings):
|
||||
assert response.data["results"][0]["id"] == str(room.id)
|
||||
|
||||
|
||||
def test_api_rooms_list_with_no_rooms(settings):
|
||||
"""Listing rooms with a valid token returns an empty list when there are no rooms."""
|
||||
settings.APPLICATION_JWT_SECRET_KEY = "devKey"
|
||||
|
||||
user = UserFactory()
|
||||
|
||||
# Generate valid token
|
||||
token = generate_test_token(user, [ApplicationScope.ROOMS_LIST])
|
||||
|
||||
client = APIClient()
|
||||
client.credentials(HTTP_AUTHORIZATION=f"Bearer {token}")
|
||||
response = client.get("/external-api/v1.0/rooms/")
|
||||
|
||||
assert response.status_code == 200
|
||||
assert response.data["count"] == 0
|
||||
assert response.data["results"] == []
|
||||
|
||||
|
||||
def test_api_rooms_list_with_expired_token(settings):
|
||||
"""Listing rooms with expired token should return 401."""
|
||||
settings.APPLICATION_JWT_SECRET_KEY = "devKey"
|
||||
@@ -92,8 +130,8 @@ def test_api_rooms_list_with_expired_token(settings):
|
||||
|
||||
|
||||
@responses.activate
|
||||
def test_api_rooms_list_with_invalid_token(settings):
|
||||
"""Listing rooms with invalid token should return 400."""
|
||||
def test_api_rooms_list_with_invalid_rs_token(settings):
|
||||
"""Listing rooms with invalid resource server token should return 400."""
|
||||
|
||||
settings.OIDC_OP_INTROSPECTION_ENDPOINT = "https://oidc.example.com/introspect"
|
||||
settings.OIDC_OP_URL = "https://oidc.example.com"
|
||||
@@ -130,7 +168,27 @@ def test_api_rooms_list_missing_scope(settings):
|
||||
response = client.get("/external-api/v1.0/rooms/")
|
||||
|
||||
assert response.status_code == 403
|
||||
assert "Insufficient permissions. Required scope: rooms:list" in str(response.data)
|
||||
assert (
|
||||
"insufficient permissions. required scope: rooms:list"
|
||||
in str(response.data).lower()
|
||||
)
|
||||
|
||||
|
||||
def test_api_rooms_list_no_scope(settings):
|
||||
"""Listing rooms without any scope should return 403."""
|
||||
settings.APPLICATION_JWT_SECRET_KEY = "devKey"
|
||||
|
||||
user = UserFactory()
|
||||
|
||||
# Token without scope
|
||||
token = generate_test_token(user, [])
|
||||
|
||||
client = APIClient()
|
||||
client.credentials(HTTP_AUTHORIZATION=f"Bearer {token}")
|
||||
response = client.get("/external-api/v1.0/rooms/")
|
||||
|
||||
assert response.status_code == 403
|
||||
assert "insufficient permissions." in str(response.data).lower()
|
||||
|
||||
|
||||
def test_api_rooms_list_filters_by_user(settings):
|
||||
@@ -144,7 +202,9 @@ def test_api_rooms_list_filters_by_user(settings):
|
||||
room2 = RoomFactory(users=[(user2, RoleChoices.OWNER)])
|
||||
room3 = RoomFactory(users=[(user1, RoleChoices.MEMBER)])
|
||||
|
||||
token = generate_test_token(user1, [ApplicationScope.ROOMS_LIST])
|
||||
token = generate_test_token(
|
||||
user1, [ApplicationScope.ROOMS_LIST, ApplicationScope.ROOMS_CREATE]
|
||||
)
|
||||
|
||||
client = APIClient()
|
||||
client.credentials(HTTP_AUTHORIZATION=f"Bearer {token}")
|
||||
@@ -158,6 +218,84 @@ def test_api_rooms_list_filters_by_user(settings):
|
||||
assert str(room2.id) not in returned_ids
|
||||
|
||||
|
||||
def test_api_rooms_retrieve_requires_authentication(settings):
|
||||
"""Retrieving rooms without authentication should return 401."""
|
||||
|
||||
settings.APPLICATION_JWT_SECRET_KEY = "devKey"
|
||||
|
||||
user1 = UserFactory()
|
||||
room1 = RoomFactory(users=[(user1, RoleChoices.OWNER)])
|
||||
|
||||
client = APIClient()
|
||||
response = client.get(f"/external-api/v1.0/rooms/{room1.id}/")
|
||||
|
||||
assert response.status_code == 401
|
||||
|
||||
|
||||
def test_api_rooms_retrieve_inactive_user(settings):
|
||||
"""Retrieve should return 401 if user is inactive."""
|
||||
settings.APPLICATION_JWT_SECRET_KEY = "devKey"
|
||||
|
||||
user1 = UserFactory(is_active=False)
|
||||
room1 = RoomFactory(users=[(user1, RoleChoices.OWNER)])
|
||||
|
||||
token = generate_test_token(user1, [ApplicationScope.ROOMS_LIST])
|
||||
|
||||
client = APIClient()
|
||||
client.credentials(HTTP_AUTHORIZATION=f"Bearer {token}")
|
||||
response = client.get(f"/external-api/v1.0/rooms/{room1.id}/")
|
||||
|
||||
assert response.status_code == 401
|
||||
assert "user account is disabled" in str(response.data).lower()
|
||||
|
||||
|
||||
def test_api_rooms_retrieve_with_expired_token(settings):
|
||||
"""Retrieving rooms with expired token should return 401."""
|
||||
settings.APPLICATION_JWT_SECRET_KEY = "devKey"
|
||||
settings.APPLICATION_JWT_EXPIRATION_SECONDS = 0
|
||||
|
||||
user = UserFactory()
|
||||
room = RoomFactory(users=[(user, RoleChoices.OWNER)])
|
||||
|
||||
# Generate expired token
|
||||
token = generate_test_token(user, [ApplicationScope.ROOMS_CREATE])
|
||||
|
||||
client = APIClient()
|
||||
client.credentials(HTTP_AUTHORIZATION=f"Bearer {token}")
|
||||
response = client.get(f"/external-api/v1.0/rooms/{room.id}/")
|
||||
|
||||
assert response.status_code == 401
|
||||
assert "expired" in str(response.data).lower()
|
||||
|
||||
|
||||
@responses.activate
|
||||
def test_api_rooms_retrieve_with_invalid_rs_token(settings):
|
||||
"""Retrieving rooms with invalid resource server token should return 400."""
|
||||
|
||||
settings.OIDC_OP_INTROSPECTION_ENDPOINT = "https://oidc.example.com/introspect"
|
||||
settings.OIDC_OP_URL = "https://oidc.example.com"
|
||||
|
||||
responses.add(
|
||||
responses.POST,
|
||||
"https://oidc.example.com/introspect",
|
||||
json={
|
||||
"iss": "https://oidc.example.com",
|
||||
"active": False,
|
||||
},
|
||||
)
|
||||
|
||||
user = UserFactory()
|
||||
room = RoomFactory(users=[(user, RoleChoices.OWNER)])
|
||||
|
||||
client = APIClient()
|
||||
client.credentials(HTTP_AUTHORIZATION="Bearer invalid-token-123")
|
||||
response = client.get(f"/external-api/v1.0/rooms/{room.id}/")
|
||||
|
||||
# Return 400 instead of 401 because ResourceServerAuthentication raises
|
||||
# SuspiciousOperation when the introspected user is not active
|
||||
assert response.status_code == 400
|
||||
|
||||
|
||||
def test_api_rooms_retrieve_requires_scope(settings):
|
||||
"""Retrieving a room requires ROOMS_RETRIEVE scope."""
|
||||
settings.APPLICATION_JWT_SECRET_KEY = "devKey"
|
||||
@@ -178,6 +316,24 @@ def test_api_rooms_retrieve_requires_scope(settings):
|
||||
)
|
||||
|
||||
|
||||
def test_api_rooms_retrieve_no_scope(settings):
|
||||
"""Retrieving rooms without any scope should return 403."""
|
||||
settings.APPLICATION_JWT_SECRET_KEY = "devKey"
|
||||
|
||||
user = UserFactory()
|
||||
|
||||
# Token without scope
|
||||
token = generate_test_token(user, [])
|
||||
room = RoomFactory(users=[(user, RoleChoices.OWNER)])
|
||||
|
||||
client = APIClient()
|
||||
client.credentials(HTTP_AUTHORIZATION=f"Bearer {token}")
|
||||
response = client.get(f"/external-api/v1.0/rooms/{room.id}/")
|
||||
|
||||
assert response.status_code == 403
|
||||
assert "insufficient permissions." in str(response.data).lower()
|
||||
|
||||
|
||||
def test_api_rooms_retrieve_success(settings):
|
||||
"""Retrieving a room with correct scope should succeed."""
|
||||
settings.APPLICATION_JWT_SECRET_KEY = "devKey"
|
||||
@@ -224,7 +380,9 @@ def test_api_rooms_retrieve_success_by_user(settings):
|
||||
room3 = RoomFactory(users=[(user1, RoleChoices.MEMBER)])
|
||||
room4 = RoomFactory(users=[(user1, RoleChoices.ADMIN)])
|
||||
|
||||
token = generate_test_token(user1, [ApplicationScope.ROOMS_RETRIEVE])
|
||||
token = generate_test_token(
|
||||
user1, [ApplicationScope.ROOMS_RETRIEVE, ApplicationScope.ROOMS_LIST]
|
||||
)
|
||||
|
||||
client = APIClient()
|
||||
client.credentials(HTTP_AUTHORIZATION=f"Bearer {token}")
|
||||
@@ -251,6 +409,91 @@ def test_api_rooms_retrieve_success_by_user(settings):
|
||||
assert response.status_code == 200
|
||||
|
||||
|
||||
def test_api_rooms_retrieve_not_found(settings):
|
||||
"""Retrieving a non-existing room with correct scope should return a 404."""
|
||||
settings.APPLICATION_JWT_SECRET_KEY = "devKey"
|
||||
|
||||
user = UserFactory()
|
||||
token = generate_test_token(user, [ApplicationScope.ROOMS_RETRIEVE])
|
||||
|
||||
client = APIClient()
|
||||
client.credentials(HTTP_AUTHORIZATION=f"Bearer {token}")
|
||||
response = client.get(f"/external-api/v1.0/rooms/{uuid.uuid4()}/")
|
||||
|
||||
assert response.status_code == 404
|
||||
assert "no room matches the given query." in str(response.data).lower()
|
||||
|
||||
|
||||
def test_api_rooms_create_requires_authentication(settings):
|
||||
"""Creating rooms without authentication should return 401."""
|
||||
|
||||
settings.APPLICATION_JWT_SECRET_KEY = "devKey"
|
||||
|
||||
client = APIClient()
|
||||
response = client.post("/external-api/v1.0/rooms/")
|
||||
|
||||
assert response.status_code == 401
|
||||
|
||||
|
||||
def test_api_rooms_create_with_expired_token(settings):
|
||||
"""Creating rooms with expired token should return 401."""
|
||||
settings.APPLICATION_JWT_SECRET_KEY = "devKey"
|
||||
settings.APPLICATION_JWT_EXPIRATION_SECONDS = 0
|
||||
|
||||
user = UserFactory()
|
||||
|
||||
# Generate expired token
|
||||
token = generate_test_token(user, [ApplicationScope.ROOMS_CREATE])
|
||||
|
||||
client = APIClient()
|
||||
client.credentials(HTTP_AUTHORIZATION=f"Bearer {token}")
|
||||
response = client.post("/external-api/v1.0/rooms/")
|
||||
|
||||
assert response.status_code == 401
|
||||
assert "expired" in str(response.data).lower()
|
||||
|
||||
|
||||
@responses.activate
|
||||
def test_api_rooms_create_with_invalid_rs_token(settings):
|
||||
"""Creating rooms with invalid resource server token should return 400."""
|
||||
|
||||
settings.OIDC_OP_INTROSPECTION_ENDPOINT = "https://oidc.example.com/introspect"
|
||||
settings.OIDC_OP_URL = "https://oidc.example.com"
|
||||
|
||||
responses.add(
|
||||
responses.POST,
|
||||
"https://oidc.example.com/introspect",
|
||||
json={
|
||||
"iss": "https://oidc.example.com",
|
||||
"active": False,
|
||||
},
|
||||
)
|
||||
|
||||
client = APIClient()
|
||||
client.credentials(HTTP_AUTHORIZATION="Bearer invalid-token-123")
|
||||
response = client.post("/external-api/v1.0/rooms/")
|
||||
|
||||
# Return 400 instead of 401 because ResourceServerAuthentication raises
|
||||
# SuspiciousOperation when the introspected user is not active
|
||||
assert response.status_code == 400
|
||||
|
||||
|
||||
def test_api_rooms_create_inactive_user(settings):
|
||||
"""Create should return 401 if user is inactive."""
|
||||
settings.APPLICATION_JWT_SECRET_KEY = "devKey"
|
||||
|
||||
user1 = UserFactory(is_active=False)
|
||||
|
||||
token = generate_test_token(user1, [ApplicationScope.ROOMS_CREATE])
|
||||
|
||||
client = APIClient()
|
||||
client.credentials(HTTP_AUTHORIZATION=f"Bearer {token}")
|
||||
response = client.post("/external-api/v1.0/rooms/")
|
||||
|
||||
assert response.status_code == 401
|
||||
assert "user account is disabled" in str(response.data).lower()
|
||||
|
||||
|
||||
def test_api_rooms_create_requires_scope(settings):
|
||||
"""Creating a room requires ROOMS_CREATE scope."""
|
||||
settings.APPLICATION_JWT_SECRET_KEY = "devKey"
|
||||
@@ -264,18 +507,38 @@ def test_api_rooms_create_requires_scope(settings):
|
||||
response = client.post("/external-api/v1.0/rooms/", {}, format="json")
|
||||
|
||||
assert response.status_code == 403
|
||||
assert "Insufficient permissions. Required scope: rooms:create" in str(
|
||||
response.data
|
||||
assert (
|
||||
"insufficient permissions. required scope: rooms:create"
|
||||
in str(response.data).lower()
|
||||
)
|
||||
|
||||
|
||||
def test_api_rooms_create_no_scope(settings):
|
||||
"""Creating rooms without any scope should return 403."""
|
||||
settings.APPLICATION_JWT_SECRET_KEY = "devKey"
|
||||
|
||||
user = UserFactory()
|
||||
|
||||
# Token without scope
|
||||
token = generate_test_token(user, [])
|
||||
|
||||
client = APIClient()
|
||||
client.credentials(HTTP_AUTHORIZATION=f"Bearer {token}")
|
||||
response = client.post("/external-api/v1.0/rooms/")
|
||||
|
||||
assert response.status_code == 403
|
||||
assert "insufficient permissions." in str(response.data).lower()
|
||||
|
||||
|
||||
def test_api_rooms_create_success(settings):
|
||||
"""Creating a room with correct scope should succeed."""
|
||||
settings.APPLICATION_JWT_SECRET_KEY = "devKey"
|
||||
|
||||
user = UserFactory()
|
||||
|
||||
token = generate_test_token(user, [ApplicationScope.ROOMS_CREATE])
|
||||
token = generate_test_token(
|
||||
user, [ApplicationScope.ROOMS_CREATE, ApplicationScope.ROOMS_LIST]
|
||||
)
|
||||
|
||||
client = APIClient()
|
||||
client.credentials(HTTP_AUTHORIZATION=f"Bearer {token}")
|
||||
@@ -284,6 +547,8 @@ def test_api_rooms_create_success(settings):
|
||||
assert response.status_code == 201
|
||||
assert "id" in response.data
|
||||
assert "slug" in response.data
|
||||
assert "name" in response.data
|
||||
assert response.data["name"] == response.data["slug"]
|
||||
|
||||
# Verify room was created with user as owner
|
||||
room = Room.objects.get(id=response.data["id"])
|
||||
@@ -291,6 +556,72 @@ def test_api_rooms_create_success(settings):
|
||||
assert room.access_level == "trusted"
|
||||
|
||||
|
||||
def test_api_rooms_create_readonly_enforcement(settings):
|
||||
"""Creating a room succeeds and any provided read-only fields are ignored."""
|
||||
settings.APPLICATION_JWT_SECRET_KEY = "devKey"
|
||||
|
||||
user = UserFactory()
|
||||
|
||||
token = generate_test_token(user, [ApplicationScope.ROOMS_CREATE])
|
||||
|
||||
client = APIClient()
|
||||
client.credentials(HTTP_AUTHORIZATION=f"Bearer {token}")
|
||||
response = client.post(
|
||||
"/external-api/v1.0/rooms/",
|
||||
{
|
||||
"id": "fake-id",
|
||||
"slug": "fake-slug",
|
||||
"name": "fake-name",
|
||||
"access_level": "public",
|
||||
},
|
||||
format="json",
|
||||
)
|
||||
|
||||
assert response.status_code == 201
|
||||
assert "slug" in response.data
|
||||
assert response.data["id"] != "fake-id"
|
||||
assert "name" in response.data
|
||||
assert response.data["slug"] != "fake-slug"
|
||||
assert "id" in response.data
|
||||
assert response.data["name"] != "fake-name"
|
||||
|
||||
# Verify room was created with user as owner
|
||||
room = Room.objects.get(id=response.data["id"])
|
||||
assert room.get_role(user) == RoleChoices.OWNER
|
||||
assert room.access_level == "trusted"
|
||||
|
||||
|
||||
def test_api_rooms_unknown_actions(settings):
|
||||
"""Updating or deleting a room are not supported yet."""
|
||||
settings.APPLICATION_JWT_SECRET_KEY = "devKey"
|
||||
|
||||
user = UserFactory()
|
||||
room = RoomFactory(users=[(user, RoleChoices.OWNER)])
|
||||
|
||||
token = generate_test_token(
|
||||
user,
|
||||
[
|
||||
ApplicationScope.ROOMS_RETRIEVE,
|
||||
ApplicationScope.ROOMS_DELETE,
|
||||
ApplicationScope.ROOMS_UPDATE,
|
||||
],
|
||||
)
|
||||
|
||||
client = APIClient()
|
||||
client.credentials(HTTP_AUTHORIZATION=f"Bearer {token}")
|
||||
response = client.delete(f"/external-api/v1.0/rooms/{room.id}/")
|
||||
|
||||
assert response.status_code == 403
|
||||
assert "insufficient permissions. unknown action." in str(response.data).lower()
|
||||
|
||||
client = APIClient()
|
||||
client.credentials(HTTP_AUTHORIZATION=f"Bearer {token}")
|
||||
response = client.patch(f"/external-api/v1.0/rooms/{room.id}/")
|
||||
|
||||
assert response.status_code == 403
|
||||
assert "insufficient permissions. unknown action." in str(response.data).lower()
|
||||
|
||||
|
||||
def test_api_rooms_response_no_url(settings):
|
||||
"""Response should not include url field when APPLICATION_BASE_URL is None."""
|
||||
settings.APPLICATION_JWT_SECRET_KEY = "devKey"
|
||||
@@ -357,7 +688,72 @@ def test_api_rooms_token_without_delegated_flag(settings):
|
||||
response = client.get("/external-api/v1.0/rooms/")
|
||||
|
||||
assert response.status_code == 401
|
||||
assert "Invalid token type." in str(response.data)
|
||||
assert "invalid token type." in str(response.data).lower()
|
||||
|
||||
|
||||
@mock.patch.object(ResourceServerAuthentication, "authenticate", return_value=None)
|
||||
def test_api_rooms_token_invalid_signature(mock_rs_authenticate, settings):
|
||||
"""Token signed with an invalid key should defer to the next authentication."""
|
||||
settings.APPLICATION_JWT_SECRET_KEY = "devKey"
|
||||
user = UserFactory()
|
||||
|
||||
# Generate token without delegated flag
|
||||
now = datetime.now(timezone.utc)
|
||||
payload = {
|
||||
"iss": settings.APPLICATION_JWT_ISSUER,
|
||||
"aud": settings.APPLICATION_JWT_AUDIENCE,
|
||||
"iat": now,
|
||||
"exp": now + timedelta(hours=1),
|
||||
"client_id": "test-client",
|
||||
"scope": "rooms:list",
|
||||
"user_id": str(user.id),
|
||||
"delegated": True,
|
||||
}
|
||||
token = jwt.encode(
|
||||
payload,
|
||||
"invalid-private-key",
|
||||
algorithm=settings.APPLICATION_JWT_ALG,
|
||||
)
|
||||
|
||||
client = APIClient()
|
||||
client.credentials(HTTP_AUTHORIZATION=f"Bearer {token}")
|
||||
response = client.get("/external-api/v1.0/rooms/")
|
||||
|
||||
mock_rs_authenticate.assert_called()
|
||||
assert response.status_code == 401
|
||||
|
||||
|
||||
@mock.patch.object(ResourceServerAuthentication, "authenticate", return_value=None)
|
||||
def test_api_rooms_token_invalid_alg(mock_rs_authenticate, settings):
|
||||
"""Token signed with an invalid alg should defer to the next authentication."""
|
||||
settings.APPLICATION_JWT_SECRET_KEY = "devKey"
|
||||
settings.APPLICATION_JWT_ALG = "RS256"
|
||||
user = UserFactory()
|
||||
|
||||
# Generate token without delegated flag
|
||||
now = datetime.now(timezone.utc)
|
||||
payload = {
|
||||
"iss": settings.APPLICATION_JWT_ISSUER,
|
||||
"aud": settings.APPLICATION_JWT_AUDIENCE,
|
||||
"iat": now,
|
||||
"exp": now + timedelta(hours=1),
|
||||
"client_id": "test-client",
|
||||
"scope": "rooms:list",
|
||||
"user_id": str(user.id),
|
||||
"delegated": True,
|
||||
}
|
||||
token = jwt.encode(
|
||||
payload,
|
||||
settings.APPLICATION_JWT_SECRET_KEY,
|
||||
algorithm="HS256", # different value
|
||||
)
|
||||
|
||||
client = APIClient()
|
||||
client.credentials(HTTP_AUTHORIZATION=f"Bearer {token}")
|
||||
response = client.get("/external-api/v1.0/rooms/")
|
||||
|
||||
mock_rs_authenticate.assert_called()
|
||||
assert response.status_code == 401
|
||||
|
||||
|
||||
def test_api_rooms_token_missing_client_id(settings):
|
||||
@@ -387,7 +783,95 @@ def test_api_rooms_token_missing_client_id(settings):
|
||||
response = client.get("/external-api/v1.0/rooms/")
|
||||
|
||||
assert response.status_code == 401
|
||||
assert "Invalid token claims." in str(response.data)
|
||||
assert "invalid token claims." in str(response.data).lower()
|
||||
|
||||
|
||||
def test_api_rooms_token_missing_user_id(settings):
|
||||
"""Token without user_id should be rejected."""
|
||||
settings.APPLICATION_JWT_SECRET_KEY = "devKey"
|
||||
|
||||
now = datetime.now(timezone.utc)
|
||||
payload = {
|
||||
"iss": settings.APPLICATION_JWT_ISSUER,
|
||||
"aud": settings.APPLICATION_JWT_AUDIENCE,
|
||||
"iat": now,
|
||||
"exp": now + timedelta(hours=1),
|
||||
"client_id": "test-client",
|
||||
"scope": "rooms:list",
|
||||
"delegated": True,
|
||||
# Missing user_id
|
||||
}
|
||||
token = jwt.encode(
|
||||
payload,
|
||||
settings.APPLICATION_JWT_SECRET_KEY,
|
||||
algorithm=settings.APPLICATION_JWT_ALG,
|
||||
)
|
||||
|
||||
client = APIClient()
|
||||
client.credentials(HTTP_AUTHORIZATION=f"Bearer {token}")
|
||||
response = client.get("/external-api/v1.0/rooms/")
|
||||
|
||||
assert response.status_code == 401
|
||||
assert "invalid token claims." in str(response.data).lower()
|
||||
|
||||
|
||||
def test_api_rooms_token_invalid_audience(settings):
|
||||
"""Token with an invalid audience should be rejected."""
|
||||
settings.APPLICATION_JWT_SECRET_KEY = "devKey"
|
||||
user = UserFactory()
|
||||
|
||||
now = datetime.now(timezone.utc)
|
||||
payload = {
|
||||
"iss": settings.APPLICATION_JWT_ISSUER,
|
||||
"aud": "invalid-audience",
|
||||
"iat": now,
|
||||
"exp": now + timedelta(hours=1),
|
||||
"client_id": "test-client",
|
||||
"user_id": str(user.id),
|
||||
"scope": "rooms:list",
|
||||
"delegated": True,
|
||||
}
|
||||
token = jwt.encode(
|
||||
payload,
|
||||
settings.APPLICATION_JWT_SECRET_KEY,
|
||||
algorithm=settings.APPLICATION_JWT_ALG,
|
||||
)
|
||||
|
||||
client = APIClient()
|
||||
client.credentials(HTTP_AUTHORIZATION=f"Bearer {token}")
|
||||
response = client.get("/external-api/v1.0/rooms/")
|
||||
|
||||
assert response.status_code == 401
|
||||
assert "invalid token." in str(response.data).lower()
|
||||
|
||||
|
||||
def test_api_rooms_token_unknown_user(settings):
|
||||
"""Token for unknown user should be rejected."""
|
||||
settings.APPLICATION_JWT_SECRET_KEY = "devKey"
|
||||
|
||||
now = datetime.now(timezone.utc)
|
||||
payload = {
|
||||
"iss": settings.APPLICATION_JWT_ISSUER,
|
||||
"aud": settings.APPLICATION_JWT_AUDIENCE,
|
||||
"iat": now,
|
||||
"exp": now + timedelta(hours=1),
|
||||
"client_id": "test-client",
|
||||
"user_id": str(uuid.uuid4()),
|
||||
"scope": "rooms:list",
|
||||
"delegated": True,
|
||||
}
|
||||
token = jwt.encode(
|
||||
payload,
|
||||
settings.APPLICATION_JWT_SECRET_KEY,
|
||||
algorithm=settings.APPLICATION_JWT_ALG,
|
||||
)
|
||||
|
||||
client = APIClient()
|
||||
client.credentials(HTTP_AUTHORIZATION=f"Bearer {token}")
|
||||
response = client.get("/external-api/v1.0/rooms/")
|
||||
|
||||
assert response.status_code == 401
|
||||
assert "user not found." in str(response.data).lower()
|
||||
|
||||
|
||||
@responses.activate
|
||||
@@ -546,7 +1030,7 @@ def test_resource_server_authentication_successful(settings):
|
||||
"aud": "some_client_id", # settings.OIDC_RS_CLIENT_ID
|
||||
"sub": "very-specific-sub",
|
||||
"client_id": "some_service_provider",
|
||||
"scope": "openid lasuite_meet lasuite_meet:rooms:list",
|
||||
"scope": "openid lasuite_meet lasuite_meet:rooms:list lasuite_meet:rooms:retrieve",
|
||||
"active": True,
|
||||
},
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user