50 lines
1.5 KiB
Python
50 lines
1.5 KiB
Python
|
|
"""Local agent authentication dependency for LOCAL_MODE registration."""
|
||
|
|
|
||
|
|
import secrets
|
||
|
|
|
||
|
|
from fastapi import Header, HTTPException, status
|
||
|
|
|
||
|
|
from app.config import get_settings
|
||
|
|
|
||
|
|
|
||
|
|
async def verify_local_agent_key(
|
||
|
|
x_local_agent_key: str = Header(..., alias="X-Local-Agent-Key"),
|
||
|
|
) -> None:
|
||
|
|
"""
|
||
|
|
Verify LOCAL_AGENT_KEY for local agent registration.
|
||
|
|
|
||
|
|
This is a narrow-scope credential that can ONLY register the local agent.
|
||
|
|
It is NOT the same as ADMIN_API_KEY.
|
||
|
|
|
||
|
|
HTTP Status Codes:
|
||
|
|
- 404: LOCAL_MODE is false (endpoint hidden by design)
|
||
|
|
- 401: LOCAL_AGENT_KEY is missing, invalid, or not configured
|
||
|
|
|
||
|
|
Raises:
|
||
|
|
HTTPException: 404 if not in LOCAL_MODE, 401 if key is invalid
|
||
|
|
"""
|
||
|
|
settings = get_settings()
|
||
|
|
|
||
|
|
# Endpoint only exists in LOCAL_MODE (security by obscurity)
|
||
|
|
if not settings.LOCAL_MODE:
|
||
|
|
raise HTTPException(
|
||
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
||
|
|
detail="Not found",
|
||
|
|
)
|
||
|
|
|
||
|
|
# LOCAL_AGENT_KEY must be configured
|
||
|
|
if not settings.LOCAL_AGENT_KEY:
|
||
|
|
raise HTTPException(
|
||
|
|
status_code=status.HTTP_401_UNAUTHORIZED,
|
||
|
|
detail="Local agent key not configured",
|
||
|
|
headers={"WWW-Authenticate": "ApiKey"},
|
||
|
|
)
|
||
|
|
|
||
|
|
# Use timing-safe comparison to prevent timing attacks
|
||
|
|
if not secrets.compare_digest(x_local_agent_key, settings.LOCAL_AGENT_KEY):
|
||
|
|
raise HTTPException(
|
||
|
|
status_code=status.HTTP_401_UNAUTHORIZED,
|
||
|
|
detail="Invalid local agent key",
|
||
|
|
headers={"WWW-Authenticate": "ApiKey"},
|
||
|
|
)
|