Refactor error handling, validation, and schema logic; improve query performance and add shared validators

- Added reusable validation functions (`validate_password_strength`, `validate_phone_number`, etc.) to centralize schema validation in `validators.py`.
- Updated `schemas/users.py` to use shared validators, simplifying and unifying validation logic.
- Introduced new error codes (`AUTH_007`, `SYS_005`) for enhanced error specificity.
- Refactored exception handling in admin routes to use more appropriate error types (`AuthorizationError`, `DuplicateError`).
- Improved organization query performance by replacing N+1 queries with optimized methods for member counts and data aggregation.
- Strengthened security in JWT decoding to prevent algorithm confusion attacks, with strict validation of required claims and algorithm enforcement.
This commit is contained in:
Felipe Cardoso
2025-11-01 01:31:10 +01:00
parent c58cce358f
commit 9ae89a20b3
6 changed files with 378 additions and 85 deletions

View File

@@ -141,12 +141,31 @@ def decode_token(token: str, verify_type: Optional[str] = None) -> TokenPayload:
TokenMissingClaimError: If a required claim is missing
"""
try:
# Decode token with strict algorithm validation
payload = jwt.decode(
token,
settings.SECRET_KEY,
algorithms=[settings.ALGORITHM]
algorithms=[settings.ALGORITHM],
options={
"verify_signature": True,
"verify_exp": True,
"verify_iat": True,
"require": ["exp", "sub", "iat"]
}
)
# SECURITY: Explicitly verify the algorithm to prevent algorithm confusion attacks
# Decode header to check algorithm (without verification, just to inspect)
header = jwt.get_unverified_header(token)
token_algorithm = header.get("alg", "").upper()
# Reject weak or unexpected algorithms
if token_algorithm == "NONE":
raise TokenInvalidError("Algorithm 'none' is not allowed")
if token_algorithm != settings.ALGORITHM.upper():
raise TokenInvalidError(f"Invalid algorithm: {token_algorithm}")
# Check required claims before Pydantic validation
if not payload.get("sub"):
raise TokenMissingClaimError("Token missing 'sub' claim")