91 lines
3.4 KiB
Python
91 lines
3.4 KiB
Python
from django.contrib.auth.hashers import make_password
|
|
from rest_framework import status
|
|
|
|
from infrasynth.security.auth.middleware import JWTAuthenticationMiddleware
|
|
from infrasynth.security.models import APIKey
|
|
|
|
|
|
class TestAPIKeyViewSet:
|
|
def test_create_returns_full_key_once(self, authenticated_client):
|
|
resp = authenticated_client.post(
|
|
"/api/auth/api-keys/",
|
|
{"name": "CI Key", "scopes": ["read:users"]},
|
|
format="json",
|
|
)
|
|
assert resp.status_code == status.HTTP_201_CREATED
|
|
data = resp.json()
|
|
assert "key" in data
|
|
assert "prefix" in data
|
|
assert data["key"].startswith(data["prefix"] + ".")
|
|
|
|
def test_created_key_authenticates(self, authenticated_client):
|
|
resp = authenticated_client.post(
|
|
"/api/auth/api-keys/",
|
|
{"name": "CI Key", "scopes": ["read:users"]},
|
|
format="json",
|
|
)
|
|
full_key = resp.json()["key"]
|
|
from rest_framework.test import APIClient
|
|
|
|
client = APIClient()
|
|
client.credentials(HTTP_X_API_KEY=full_key)
|
|
check = client.get("/api/auth/check/")
|
|
assert check.status_code == status.HTTP_200_OK
|
|
|
|
def test_list_keys(self, authenticated_client, user):
|
|
APIKey.objects.create(
|
|
name="Old Key",
|
|
prefix="prefix01",
|
|
key_hash=make_password("secret"),
|
|
created_by=user,
|
|
)
|
|
resp = authenticated_client.get("/api/auth/api-keys/")
|
|
assert resp.status_code == status.HTTP_200_OK
|
|
assert resp.json()["count"] == 1
|
|
|
|
def test_list_never_exposes_hash(self, authenticated_client, user):
|
|
APIKey.objects.create(
|
|
name="Old Key",
|
|
prefix="prefix01",
|
|
key_hash=make_password("secret"),
|
|
created_by=user,
|
|
)
|
|
resp = authenticated_client.get("/api/auth/api-keys/")
|
|
result = resp.json()["results"][0]
|
|
assert "key" not in result
|
|
assert "key_hash" not in result
|
|
assert result["prefix"] == "prefix01"
|
|
|
|
def test_delete_key(self, authenticated_client, user):
|
|
key = APIKey.objects.create(
|
|
name="Old Key",
|
|
prefix="prefix01",
|
|
key_hash=make_password("secret"),
|
|
created_by=user,
|
|
)
|
|
resp = authenticated_client.delete(f"/api/auth/api-keys/{key.pk}/")
|
|
assert resp.status_code == status.HTTP_204_NO_CONTENT
|
|
assert not APIKey.objects.filter(pk=key.pk).exists()
|
|
|
|
def test_requires_auth(self, api_client):
|
|
resp = api_client.get("/api/auth/api-keys/")
|
|
assert resp.status_code == status.HTTP_401_UNAUTHORIZED
|
|
|
|
|
|
class TestJWTAuthenticationMiddleware:
|
|
def test_ignores_anonymous_requests(self, rf, db):
|
|
request = rf.get("/api/features/active/")
|
|
request.user = type("Anon", (), {"is_anonymous": True})()
|
|
JWTAuthenticationMiddleware(get_response=lambda r: None).process_request(request)
|
|
assert request.user.is_anonymous
|
|
|
|
def test_populates_user_from_cookie(self, rf, user):
|
|
from rest_framework_simplejwt.tokens import RefreshToken
|
|
|
|
from infrasynth.shared.crypto import encrypt
|
|
|
|
request = rf.get("/api/features/active/")
|
|
request.COOKIES["access_token"] = encrypt(str(RefreshToken.for_user(user).access_token))
|
|
request.user = type("Anon", (), {"is_anonymous": True})()
|
|
JWTAuthenticationMiddleware(get_response=lambda r: None).process_request(request)
|
|
assert request.user == user
|