File size: 4,373 Bytes
81e3673 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | """
Security test fixtures for authentication and JWT testing.
"""
import os
# Set TESTING environment variable BEFORE any imports to prevent
# recursion in models_registration.py during test setup
os.environ["TESTING"] = "1"
import pytest
from datetime import datetime, timedelta
try:
from freezegun import freeze_time
except ImportError:
# freezegun not available, create a no-op context manager
class freeze_time:
def __init__(self, *args, **kwargs):
pass
def __enter__(self):
return self
def __exit__(self, *args):
pass
from jose import jwt
from sqlalchemy.orm import Session
from tests.property_tests.conftest import db_session
from tests.factories.user_factory import UserFactory
from core.auth import SECRET_KEY, ALGORITHM, create_access_token, get_password_hash
from core.models import User
@pytest.fixture(scope="function")
def test_user_with_password(db_session: Session):
"""Create user with known password for testing."""
from tests.factories.user_factory import UserFactory
user = UserFactory(
email="auth@test.com",
password_hash=get_password_hash("KnownPassword123!"),
_session=db_session
)
return user
@pytest.fixture(scope="function")
def valid_auth_token(test_user_with_password):
"""Create valid JWT token for test user."""
return create_access_token(data={"sub": str(test_user_with_password.id)})
@pytest.fixture(scope="function")
def expired_auth_token(test_user_with_password):
"""Create expired JWT token for testing expiration."""
with freeze_time("2026-02-01 10:00:00"):
token = create_access_token(data={"sub": str(test_user_with_password.id)})
return token
@pytest.fixture(scope="function")
def invalid_auth_token():
"""Create invalid JWT token (malformed)."""
return "invalid.jwt.token"
@pytest.fixture(scope="function")
def tampered_token(valid_auth_token):
"""Create JWT token that has been tampered with."""
# Decode, modify, re-encode with wrong secret
try:
payload = jwt.decode(valid_auth_token, SECRET_KEY, algorithms=[ALGORITHM])
payload["admin"] = True # Add privilege escalation
# Re-encode with wrong secret
return jwt.encode(payload, "wrong_secret", algorithm=ALGORITHM)
except:
return "tampered.invalid.token"
@pytest.fixture(scope="function")
def refresh_token(test_user_with_password):
"""Create a refresh token for testing."""
# Create a token with longer expiry for refresh purposes
with freeze_time("2026-02-01 10:00:00"):
from core.auth import create_mobile_token
tokens = create_mobile_token(
test_user_with_password,
device_id="test_device_123",
expires_delta=timedelta(days=30)
)
return tokens.get("refresh_token")
def create_test_token(user_id: str, expires_delta: timedelta = None):
"""Helper to create test JWT tokens."""
return create_access_token(data={"sub": user_id}, expires_delta=expires_delta)
# =============================================================================
# Additional fixtures for authorization and input validation tests
# =============================================================================
@pytest.fixture(scope="function")
def client(db_session: Session):
"""
Create a FastAPI TestClient for testing API endpoints.
"""
from fastapi.testclient import TestClient
from core.database import get_db
from main_api_app import app
# Override the database dependency
def _get_db():
try:
yield db_session
finally:
pass
app.dependency_overrides[get_db] = _get_db
with TestClient(app) as test_client:
yield test_client
# Clean up
app.dependency_overrides.clear()
@pytest.fixture(scope="function")
def admin_user(db_session: Session):
"""
Create an admin user for testing.
"""
from tests.factories.user_factory import AdminUserFactory
user = AdminUserFactory(_session=db_session)
return user
@pytest.fixture(scope="function")
def admin_token(client, admin_user: User) -> str:
"""
Get an authentication token for the admin user.
"""
# Create token directly for testing
return create_access_token(data={"sub": str(admin_user.id)})
|