fix(auth): accept configured public origin for sign-in
Magent CI/CD / verify (push) Successful in 4m15s
Magent CI/CD / deploy-beta (push) Skipped

This commit is contained in:
2026-09-19 12:26:09 +12:00
parent a6a4a9aa24
commit 0f4071c970
8 changed files with 335 additions and 13 deletions
+3 -3
View File
@@ -53,6 +53,7 @@ from .logging_config import (
from .runtime import get_runtime_settings
from .metrics import record_api, start_metrics
from .secret_storage import validate_secret_storage_configuration
from .services.request_origins import is_allowed_request_origin
logger = logging.getLogger(__name__)
_background_tasks: list[asyncio.Task[None]] = []
@@ -87,9 +88,8 @@ async def log_requests_and_add_security_headers(request: Request, call_next):
)
request.state.request_id = request_id
if request.method.upper() not in {"GET", "HEAD", "OPTIONS"}:
origin = str(request.headers.get("origin") or "").rstrip("/")
allowed_origin = str(settings.cors_allow_origin or "").rstrip("/")
if origin and origin != allowed_origin:
origin = str(request.headers.get("origin") or "")
if origin and not is_allowed_request_origin(origin):
record_api(request, 403, 0.0)
if operation_id and operation_token is not None:
finish_operation(operation_id, success=False, status_code=403)
+41
View File
@@ -0,0 +1,41 @@
"""State-changing requests may originate only from explicitly configured sites.
The public Hosting & proxy URL can be stored in the database, while the CORS
environment setting still has its localhost default on an upgraded install.
Never infer a trusted origin from request Host or forwarded headers.
"""
from urllib.parse import urlsplit
from ..config import settings
from .public_urls import magent_public_url, valid_public_url
def _origin(value: str, *, configured_url: bool = False) -> tuple[str, str, int] | None:
value = str(value or "")
if any(character.isspace() or ord(character) < 33 or ord(character) == 127 for character in value):
return None
if "?" in value or "#" in value:
return None
validated = valid_public_url(value)
if not validated:
return None
parsed = urlsplit(value)
if parsed.username is not None or parsed.password is not None:
return None
if not configured_url and parsed.path:
return None
return (
parsed.scheme.lower(),
parsed.hostname.lower(),
parsed.port or (443 if parsed.scheme == "https" else 80),
)
def is_allowed_request_origin(origin: str) -> bool:
candidate = _origin(origin)
if candidate is None:
return False
if candidate == _origin(str(settings.cors_allow_origin or "").rstrip("/")):
return True
return candidate == _origin(magent_public_url(), configured_url=True)