This commit is contained in:
2025-09-18 09:03:11 +02:00
parent b2b240c16a
commit 9db8499a56
4 changed files with 30 additions and 2 deletions

View File

@@ -159,17 +159,35 @@ async def login(
): ):
"""Login user and return access tokens""" """Login user and return access tokens"""
logger.info(f"Login attempt for email: {user_data.email}")
start_time = datetime.utcnow()
# Get user by email # Get user by email
stmt = select(User).where(User.email == user_data.email) stmt = select(User).where(User.email == user_data.email)
result = await db.execute(stmt) result = await db.execute(stmt)
user = result.scalar_one_or_none() user = result.scalar_one_or_none()
if not user or not verify_password(user_data.password, user.hashed_password): if not user:
logger.warning(f"User not found: {user_data.email}")
raise HTTPException( raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED, status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect email or password" detail="Incorrect email or password"
) )
logger.info(f"User found, starting password verification...")
verify_start = datetime.utcnow()
if not verify_password(user_data.password, user.hashed_password):
verify_end = datetime.utcnow()
logger.warning(f"Password verification failed. Time taken: {(verify_end - verify_start).total_seconds()} seconds")
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect email or password"
)
verify_end = datetime.utcnow()
logger.info(f"Password verification successful. Time taken: {(verify_end - verify_start).total_seconds()} seconds")
if not user.is_active: if not user.is_active:
raise HTTPException( raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED, status_code=status.HTTP_401_UNAUTHORIZED,

View File

@@ -34,6 +34,7 @@ class Settings(BaseSettings):
REFRESH_TOKEN_EXPIRE_MINUTES: int = int(os.getenv("REFRESH_TOKEN_EXPIRE_MINUTES", "10080")) # 7 days REFRESH_TOKEN_EXPIRE_MINUTES: int = int(os.getenv("REFRESH_TOKEN_EXPIRE_MINUTES", "10080")) # 7 days
SESSION_EXPIRE_MINUTES: int = int(os.getenv("SESSION_EXPIRE_MINUTES", "1440")) # 24 hours SESSION_EXPIRE_MINUTES: int = int(os.getenv("SESSION_EXPIRE_MINUTES", "1440")) # 24 hours
API_KEY_PREFIX: str = os.getenv("API_KEY_PREFIX", "en_") API_KEY_PREFIX: str = os.getenv("API_KEY_PREFIX", "en_")
BCRYPT_ROUNDS: int = int(os.getenv("BCRYPT_ROUNDS", "6")) # Bcrypt work factor - lower for production performance
# Admin user provisioning (used only on first startup) # Admin user provisioning (used only on first startup)
ADMIN_EMAIL: str = os.getenv("ADMIN_EMAIL") ADMIN_EMAIL: str = os.getenv("ADMIN_EMAIL")

View File

@@ -20,7 +20,12 @@ from app.utils.exceptions import AuthenticationError, AuthorizationError
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
# Password hashing # Password hashing
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") # Use a lower work factor for better performance in production
pwd_context = CryptContext(
schemes=["bcrypt"],
deprecated="auto",
bcrypt__rounds=settings.BCRYPT_ROUNDS
)
# JWT token handling # JWT token handling
security = HTTPBearer() security = HTTPBearer()

View File

@@ -13,6 +13,10 @@ http {
proxy_read_timeout 600; proxy_read_timeout 600;
send_timeout 600; send_timeout 600;
# FastAPI timeout handling
proxy_read_timeout 300s;
proxy_send_timeout 300s;
upstream backend { upstream backend {
server enclava-backend:8000; server enclava-backend:8000;
} }