chore: prepare repository for public release
This commit is contained in:
@@ -2,6 +2,7 @@ from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from datetime import UTC, datetime
|
||||
from ipaddress import ip_address, ip_network
|
||||
|
||||
from fastapi import APIRouter, Depends, Request, Response, status
|
||||
from fastapi.responses import RedirectResponse
|
||||
@@ -20,6 +21,43 @@ router = APIRouter(prefix="/auth", tags=["auth"])
|
||||
COOKIE_NAME = "geointel_session"
|
||||
OIDC_FLOW_COOKIE_NAME = "geointel_oidc_flow"
|
||||
logger = logging.getLogger("geointel.auth")
|
||||
_TRUSTED_PROXY_NETWORKS = (
|
||||
ip_network("127.0.0.0/8"),
|
||||
ip_network("::1/128"),
|
||||
ip_network("172.16.0.0/12"),
|
||||
)
|
||||
|
||||
|
||||
def _peer_is_trusted_proxy(request: Request) -> bool:
|
||||
if request.client is None:
|
||||
return False
|
||||
try:
|
||||
peer_address = ip_address(request.client.host)
|
||||
except ValueError:
|
||||
return False
|
||||
return any(peer_address in network for network in _TRUSTED_PROXY_NETWORKS)
|
||||
|
||||
|
||||
def _request_is_https(request: Request) -> bool:
|
||||
if request.url.scheme == "https":
|
||||
return True
|
||||
if not _peer_is_trusted_proxy(request):
|
||||
return False
|
||||
forwarded_proto = request.headers.get("x-forwarded-proto", "").split(",", 1)[0].strip().lower()
|
||||
return forwarded_proto == "https"
|
||||
|
||||
|
||||
def _client_host(request: Request) -> str:
|
||||
peer = request.client.host if request.client else "unknown"
|
||||
if not _peer_is_trusted_proxy(request):
|
||||
return peer
|
||||
forwarded = request.headers.get("x-real-ip", "").strip()
|
||||
if not forwarded:
|
||||
return peer
|
||||
try:
|
||||
return str(ip_address(forwarded))
|
||||
except ValueError:
|
||||
return peer
|
||||
|
||||
|
||||
def _session_from_principal(
|
||||
@@ -73,13 +111,12 @@ def _set_session_cookie(
|
||||
token: str,
|
||||
max_age: int,
|
||||
) -> None:
|
||||
forwarded_proto = request.headers.get("x-forwarded-proto", "").split(",", 1)[0].strip().lower()
|
||||
response.set_cookie(
|
||||
key=COOKIE_NAME,
|
||||
value=token,
|
||||
max_age=max_age,
|
||||
httponly=True,
|
||||
secure=forwarded_proto == "https" or request.url.scheme == "https",
|
||||
secure=_request_is_https(request),
|
||||
samesite="strict",
|
||||
path="/",
|
||||
)
|
||||
@@ -99,7 +136,13 @@ def login(payload: AuthLoginRequest, request: Request, response: Response) -> Au
|
||||
message="Operator authentication is not enabled on this runtime",
|
||||
status_code=status.HTTP_409_CONFLICT,
|
||||
)
|
||||
client_host = request.client.host if request.client else "unknown"
|
||||
if settings.auth_require_https and not _request_is_https(request):
|
||||
raise AppError(
|
||||
code="AUTH_HTTPS_REQUIRED",
|
||||
message="Operator authentication requires HTTPS on this runtime",
|
||||
status_code=status.HTTP_426_UPGRADE_REQUIRED,
|
||||
)
|
||||
client_host = _client_host(request)
|
||||
throttle_key = f"{client_host}:{payload.username.casefold()}"
|
||||
retry_after = AuthService.retry_after_seconds(throttle_key)
|
||||
if retry_after:
|
||||
|
||||
Reference in New Issue
Block a user