fix: API token project ownership check
- API tokens now verify project belongs to token owner before access - Researcher tokens only access research/general docs in owner's projects - Developer tokens only access development/general docs in owner's projects - Viewer tokens have read-only access to all doc types in owner's projects - Add test for cross-user project access prevention
This commit is contained in:
@@ -257,3 +257,88 @@ async def test_api_token_auth_flow(client, admin_user):
|
||||
headers={"Authorization": f"Bearer {researcher_token}"}
|
||||
)
|
||||
assert get_resp.status_code == 403
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_api_token_cannot_access_other_user_project(client, admin_user):
|
||||
"""Test that API token can only access projects belonging to the token owner."""
|
||||
# Create another user
|
||||
import uuid
|
||||
import bcrypt
|
||||
from sqlalchemy import text
|
||||
|
||||
password_hash = bcrypt.hashpw("user2pass".encode(), bcrypt.gensalt()).decode()
|
||||
|
||||
async with async_engine.begin() as conn:
|
||||
user2_id = str(uuid.uuid4())
|
||||
await conn.execute(
|
||||
text("""
|
||||
INSERT INTO agents (id, username, password_hash, role, is_deleted, created_at, updated_at)
|
||||
VALUES (:id, :username, :password_hash, 'agent', 0, datetime('now'), datetime('now'))
|
||||
"""),
|
||||
{
|
||||
"id": user2_id,
|
||||
"username": "user2",
|
||||
"password_hash": password_hash
|
||||
}
|
||||
)
|
||||
|
||||
# Login as user2
|
||||
login_resp = await client.post(
|
||||
"/api/v1/auth/login",
|
||||
json={"username": "user2", "password": "user2pass"}
|
||||
)
|
||||
user2_token = login_resp.json()["access_token"]
|
||||
|
||||
# Create project by user2
|
||||
proj_resp = await client.post(
|
||||
"/api/v1/projects",
|
||||
json={"name": "User2 Project"},
|
||||
headers={"Authorization": f"Bearer {user2_token}"}
|
||||
)
|
||||
user2_proj_id = proj_resp.json()["id"]
|
||||
|
||||
# Create document in user2's project
|
||||
doc_resp = await client.post(
|
||||
f"/api/v1/projects/{user2_proj_id}/documents",
|
||||
json={"title": "User2 Doc", "content": "Content", "agent_type": "general"},
|
||||
headers={"Authorization": f"Bearer {user2_token}"}
|
||||
)
|
||||
user2_doc_id = doc_resp.json()["id"]
|
||||
|
||||
# Admin creates a researcher token
|
||||
gen_resp = await client.post(
|
||||
"/api/v1/auth/token/generate",
|
||||
json={"name": "research-token", "role": "researcher"},
|
||||
headers={"Authorization": f"Bearer {admin_user}"}
|
||||
)
|
||||
researcher_token = gen_resp.json()["token"]
|
||||
|
||||
# Admin creates a project and document
|
||||
admin_proj_resp = await client.post(
|
||||
"/api/v1/projects",
|
||||
json={"name": "Admin Project"},
|
||||
headers={"Authorization": f"Bearer {admin_user}"}
|
||||
)
|
||||
admin_proj_id = admin_proj_resp.json()["id"]
|
||||
|
||||
admin_doc_resp = await client.post(
|
||||
f"/api/v1/projects/{admin_proj_id}/documents",
|
||||
json={"title": "Admin Doc", "content": "Content", "agent_type": "research"},
|
||||
headers={"Authorization": f"Bearer {admin_user}"}
|
||||
)
|
||||
admin_doc_id = admin_doc_resp.json()["id"]
|
||||
|
||||
# Researcher token should NOT be able to access user2's project/document
|
||||
get_resp = await client.get(
|
||||
f"/api/v1/documents/{user2_doc_id}",
|
||||
headers={"Authorization": f"Bearer {researcher_token}"}
|
||||
)
|
||||
assert get_resp.status_code == 403
|
||||
|
||||
# Researcher token SHOULD be able to access admin's research document
|
||||
get_resp = await client.get(
|
||||
f"/api/v1/documents/{admin_doc_id}",
|
||||
headers={"Authorization": f"Bearer {researcher_token}"}
|
||||
)
|
||||
assert get_resp.status_code == 200
|
||||
|
||||
Reference in New Issue
Block a user