fix(security): improve api key and jwt validation handling
This commit is contained in:
parent
574d82f3c4
commit
1c6c45465f
2 changed files with 21 additions and 7 deletions
17
api.py
17
api.py
|
|
@ -278,18 +278,21 @@ def get_auth_schemes_for_user(swagger_user: dict) -> dict:
|
||||||
allowed_tags = swagger_user.get("allowed_tags")
|
allowed_tags = swagger_user.get("allowed_tags")
|
||||||
|
|
||||||
if not allowed_tags:
|
if not allowed_tags:
|
||||||
|
# Admin complet
|
||||||
return {
|
return {
|
||||||
"HTTPBearer": {
|
"HTTPBearer": {
|
||||||
"type": "http",
|
"type": "http",
|
||||||
"scheme": "bearer",
|
"scheme": "bearer",
|
||||||
"bearerFormat": "JWT",
|
"bearerFormat": "JWT",
|
||||||
"description": "Authentification JWT pour utilisateurs (POST /auth/login)",
|
"description": "🎫 Authentification JWT pour utilisateurs (POST /auth/login). "
|
||||||
|
"Utilisez SOIT JWT SOIT API Key, pas les deux.",
|
||||||
},
|
},
|
||||||
"ApiKeyAuth": {
|
"ApiKeyAuth": {
|
||||||
"type": "apiKey",
|
"type": "apiKey",
|
||||||
"in": "header",
|
"in": "header",
|
||||||
"name": "X-API-Key",
|
"name": "X-API-Key",
|
||||||
"description": "Clé API pour intégrations externes (format: sdk_live_xxx)",
|
"description": " Clé API pour intégrations externes (format: sdk_live_xxx). "
|
||||||
|
"Utilisez SOIT JWT SOIT API Key, pas les deux.",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -300,14 +303,16 @@ def get_auth_schemes_for_user(swagger_user: dict) -> dict:
|
||||||
"type": "http",
|
"type": "http",
|
||||||
"scheme": "bearer",
|
"scheme": "bearer",
|
||||||
"bearerFormat": "JWT",
|
"bearerFormat": "JWT",
|
||||||
"description": "Authentification JWT pour utilisateurs (POST /auth/login)",
|
"description": "🎫 Authentification JWT pour utilisateurs (POST /auth/login). "
|
||||||
|
"Utilisez SOIT JWT SOIT API Key, pas les deux.",
|
||||||
}
|
}
|
||||||
|
|
||||||
schemes["ApiKeyAuth"] = {
|
schemes["ApiKeyAuth"] = {
|
||||||
"type": "apiKey",
|
"type": "apiKey",
|
||||||
"in": "header",
|
"in": "header",
|
||||||
"name": "X-API-Key",
|
"name": "X-API-Key",
|
||||||
"description": "Clé API pour intégrations externes (format: sdk_live_xxx)",
|
"description": " Clé API pour intégrations externes (format: sdk_live_xxx). "
|
||||||
|
"Utilisez SOIT JWT SOIT API Key, pas les deux.",
|
||||||
}
|
}
|
||||||
|
|
||||||
return schemes
|
return schemes
|
||||||
|
|
@ -483,7 +488,9 @@ async def custom_swagger_ui(request: Request):
|
||||||
"displayRequestDuration": True,
|
"displayRequestDuration": True,
|
||||||
"filter": True,
|
"filter": True,
|
||||||
"tryItOutEnabled": True,
|
"tryItOutEnabled": True,
|
||||||
"docExpansion": "list", # Meilleure UX
|
"docExpansion": "list",
|
||||||
|
# CORRECTIF : Ne pas pré-remplir les credentials
|
||||||
|
"preAuthorizeApiKey": False,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -158,14 +158,18 @@ class ApiKeyMiddlewareHTTP(BaseHTTPMiddleware):
|
||||||
auth_header = request.headers.get("Authorization")
|
auth_header = request.headers.get("Authorization")
|
||||||
api_key_header = request.headers.get("X-API-Key")
|
api_key_header = request.headers.get("X-API-Key")
|
||||||
|
|
||||||
|
# CORRECTIF : Nettoyer et valider la clé API
|
||||||
if api_key_header:
|
if api_key_header:
|
||||||
api_key_header = api_key_header.strip()
|
api_key_header = api_key_header.strip()
|
||||||
|
# Si la clé est vide ou juste des espaces, la considérer comme absente
|
||||||
if not api_key_header or api_key_header == "":
|
if not api_key_header or api_key_header == "":
|
||||||
api_key_header = None
|
api_key_header = None
|
||||||
|
|
||||||
|
# Vérifier si c'est un token JWT Bearer
|
||||||
if auth_header and auth_header.startswith("Bearer "):
|
if auth_header and auth_header.startswith("Bearer "):
|
||||||
token = auth_header.split(" ")[1].strip()
|
token = auth_header.split(" ", 1)[1].strip()
|
||||||
|
|
||||||
|
# CORRECTIF : Vérifier si c'est une API Key envoyée par erreur dans Authorization
|
||||||
if token.startswith("sdk_live_"):
|
if token.startswith("sdk_live_"):
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"⚠️ API Key envoyée dans Authorization au lieu de X-API-Key"
|
"⚠️ API Key envoyée dans Authorization au lieu de X-API-Key"
|
||||||
|
|
@ -174,16 +178,19 @@ class ApiKeyMiddlewareHTTP(BaseHTTPMiddleware):
|
||||||
request, token, path, method, call_next
|
request, token, path, method, call_next
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# C'est un JWT valide, déléguer à FastAPI
|
||||||
logger.debug(f"🎫 JWT détecté pour {method} {path} → délégation à FastAPI")
|
logger.debug(f"🎫 JWT détecté pour {method} {path} → délégation à FastAPI")
|
||||||
request.state.authenticated_via = "jwt"
|
request.state.authenticated_via = "jwt"
|
||||||
return await call_next(request)
|
return await call_next(request)
|
||||||
|
|
||||||
|
# CORRECTIF : Si une clé API est présente ET non vide, la traiter
|
||||||
if api_key_header:
|
if api_key_header:
|
||||||
logger.debug(f"🔑 API Key détectée pour {method} {path}")
|
logger.debug(f" API Key détectée pour {method} {path}")
|
||||||
return await self._handle_api_key_auth(
|
return await self._handle_api_key_auth(
|
||||||
request, api_key_header, path, method, call_next
|
request, api_key_header, path, method, call_next
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Aucune authentification fournie, déléguer à FastAPI qui renverra 401
|
||||||
logger.debug(f"❌ Aucune auth pour {method} {path} → délégation à FastAPI")
|
logger.debug(f"❌ Aucune auth pour {method} {path} → délégation à FastAPI")
|
||||||
return await call_next(request)
|
return await call_next(request)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue