Enforce tenant isolation on verified audit firm domains
This commit is contained in:
@@ -59,6 +59,19 @@ def _normalise_session_int(value):
|
||||
return None
|
||||
|
||||
|
||||
_TENANT_BOUND_DOMAIN_TYPES = {"audit_firm_domain", "audit_firm_subdomain"}
|
||||
|
||||
|
||||
def _is_trusted_tenant_bound_domain(request: Request) -> bool:
|
||||
return (
|
||||
bool(getattr(request.state, "domain_resolved", False))
|
||||
and bool(getattr(request.state, "domain_is_verified", False))
|
||||
and (getattr(request.state, "domain_status", None) or "").strip().lower() == "active"
|
||||
and (getattr(request.state, "domain_type", None) or "").strip() in _TENANT_BOUND_DOMAIN_TYPES
|
||||
and _normalise_session_int(getattr(request.state, "domain_tenant_id", None)) is not None
|
||||
)
|
||||
|
||||
|
||||
class ContextResolveMiddleware(BaseHTTPMiddleware):
|
||||
def __init__(self, app: ASGIApp) -> None:
|
||||
super().__init__(app)
|
||||
@@ -101,22 +114,35 @@ class ContextResolveMiddleware(BaseHTTPMiddleware):
|
||||
session_tenant_code = (session.get("active_tenant_code") or session.get("tenant_code") or "").strip() or None
|
||||
session_branch_code = (session.get("active_branch_code") or session.get("branch_code") or "").strip() or None
|
||||
|
||||
domain_tenant_id = _normalise_session_int(getattr(request.state, "domain_tenant_id", None))
|
||||
domain_branch_id = _normalise_session_int(getattr(request.state, "domain_branch_id", None))
|
||||
domain_tenant_code = getattr(request.state, "domain_tenant_code", None)
|
||||
domain_branch_code = getattr(request.state, "domain_branch_code", None)
|
||||
tenant_bound_domain = _is_trusted_tenant_bound_domain(request)
|
||||
|
||||
tenant_code = (
|
||||
session_tenant_code
|
||||
or domain_tenant_code
|
||||
or (request.headers.get(_TENANT_HEADER) if trust_headers else None)
|
||||
or self.s.DEFAULT_TENANT_CODE
|
||||
)
|
||||
|
||||
branch_code = (
|
||||
session_branch_code
|
||||
or domain_branch_code
|
||||
or (request.headers.get(_BRANCH_HEADER) if trust_headers else None)
|
||||
or self.s.DEFAULT_BRANCH_CODE
|
||||
)
|
||||
# On a verified active audit-firm hostname, the domain mapping is the
|
||||
# authoritative tenant/branch context. Session selection must never
|
||||
# escape to another tenant while the user remains on that hostname.
|
||||
if tenant_bound_domain:
|
||||
active_tenant_id = domain_tenant_id
|
||||
active_branch_id = domain_branch_id if domain_branch_id is not None else session_branch_id
|
||||
tenant_code = domain_tenant_code or self.s.DEFAULT_TENANT_CODE
|
||||
branch_code = domain_branch_code or session_branch_code or self.s.DEFAULT_BRANCH_CODE
|
||||
else:
|
||||
active_tenant_id = session_tenant_id
|
||||
active_branch_id = session_branch_id
|
||||
tenant_code = (
|
||||
session_tenant_code
|
||||
or domain_tenant_code
|
||||
or (request.headers.get(_TENANT_HEADER) if trust_headers else None)
|
||||
or self.s.DEFAULT_TENANT_CODE
|
||||
)
|
||||
branch_code = (
|
||||
session_branch_code
|
||||
or domain_branch_code
|
||||
or (request.headers.get(_BRANCH_HEADER) if trust_headers else None)
|
||||
or self.s.DEFAULT_BRANCH_CODE
|
||||
)
|
||||
|
||||
year_code = (
|
||||
session.get("active_financial_year")
|
||||
@@ -124,8 +150,9 @@ class ContextResolveMiddleware(BaseHTTPMiddleware):
|
||||
or self.s.DEFAULT_YEAR_CODE
|
||||
)
|
||||
|
||||
request.state.active_tenant_id = session_tenant_id
|
||||
request.state.active_branch_id = session_branch_id
|
||||
request.state.active_tenant_id = active_tenant_id
|
||||
request.state.active_branch_id = active_branch_id
|
||||
request.state.tenant_bound_domain = tenant_bound_domain
|
||||
request.state.tenant_code = tenant_code
|
||||
request.state.branch_code = branch_code
|
||||
request.state.year_code = year_code
|
||||
|
||||
Reference in New Issue
Block a user