Add rate limiting to login endpoint
Security: - Add slowapi dependency for rate limiting - Create rate_limit.py module with configurable limits - Apply 5 requests/minute limit to login endpoint - Make rate limit configurable via ORCHARD_LOGIN_RATE_LIMIT env var Testing: - Set high rate limit (1000/min) in docker-compose.local.yml for tests - All 265 tests pass
This commit is contained in:
@@ -1,15 +1,19 @@
|
||||
from fastapi import FastAPI
|
||||
from fastapi import FastAPI, Request
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from fastapi.responses import FileResponse
|
||||
from contextlib import asynccontextmanager
|
||||
import logging
|
||||
import os
|
||||
|
||||
from slowapi import _rate_limit_exceeded_handler
|
||||
from slowapi.errors import RateLimitExceeded
|
||||
|
||||
from .config import get_settings
|
||||
from .database import init_db, SessionLocal
|
||||
from .routes import router
|
||||
from .seed import seed_database
|
||||
from .auth import create_default_admin
|
||||
from .rate_limit import limiter
|
||||
|
||||
settings = get_settings()
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
@@ -55,6 +59,10 @@ app = FastAPI(
|
||||
lifespan=lifespan,
|
||||
)
|
||||
|
||||
# Set up rate limiting
|
||||
app.state.limiter = limiter
|
||||
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)
|
||||
|
||||
# Include API routes
|
||||
app.include_router(router)
|
||||
|
||||
|
||||
16
backend/app/rate_limit.py
Normal file
16
backend/app/rate_limit.py
Normal file
@@ -0,0 +1,16 @@
|
||||
"""Rate limiting configuration for Orchard API.
|
||||
|
||||
Uses slowapi for rate limiting with IP-based keys.
|
||||
"""
|
||||
|
||||
import os
|
||||
from slowapi import Limiter
|
||||
from slowapi.util import get_remote_address
|
||||
|
||||
# Rate limiter - uses IP address as key
|
||||
limiter = Limiter(key_func=get_remote_address)
|
||||
|
||||
# Rate limit strings - configurable via environment for testing
|
||||
# Default: 5 login attempts per minute per IP
|
||||
# In tests: set ORCHARD_LOGIN_RATE_LIMIT to a high value like "1000/minute"
|
||||
LOGIN_RATE_LIMIT = os.environ.get("ORCHARD_LOGIN_RATE_LIMIT", "5/minute")
|
||||
@@ -374,9 +374,11 @@ from .auth import (
|
||||
check_project_access,
|
||||
AuthorizationService,
|
||||
)
|
||||
from .rate_limit import limiter, LOGIN_RATE_LIMIT
|
||||
|
||||
|
||||
@router.post("/api/v1/auth/login", response_model=LoginResponse)
|
||||
@limiter.limit(LOGIN_RATE_LIMIT)
|
||||
def login(
|
||||
login_request: LoginRequest,
|
||||
request: Request,
|
||||
|
||||
@@ -10,6 +10,7 @@ pydantic-settings==2.1.0
|
||||
python-jose[cryptography]==3.3.0
|
||||
passlib[bcrypt]==1.7.4
|
||||
bcrypt==4.0.1
|
||||
slowapi==0.1.9
|
||||
|
||||
# Test dependencies
|
||||
pytest>=7.4.0
|
||||
|
||||
Reference in New Issue
Block a user