fix: preserve tenant creation metadata and report authority denial
Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a07ff8-19d0-7820-b4d0-1353833cb7fc
This commit is contained in:
parent
b9ae48b00c
commit
3c85e563ee
3 changed files with 50 additions and 2 deletions
|
|
@ -52,6 +52,8 @@ class HTTPTenantManagementAdapter:
|
|||
"tenant_id": tenant,
|
||||
"identifier": tenant,
|
||||
"actor": ACTOR,
|
||||
"display_name": display_name,
|
||||
"correlation_id": correlation_id,
|
||||
}).encode(),
|
||||
headers={
|
||||
"Authorization": f"Bearer {self.bearer_token}",
|
||||
|
|
@ -65,12 +67,12 @@ class HTTPTenantManagementAdapter:
|
|||
with urlopen(request, timeout=self.timeout) as response:
|
||||
result = json.loads(response.read())
|
||||
except HTTPError as exc:
|
||||
exc.read(4096)
|
||||
if exc.code == 409:
|
||||
exc.read(4096)
|
||||
return TenantProvisioningResult(
|
||||
tenant=tenant, status="existing", resumed=True, external_ref=tenant,
|
||||
)
|
||||
raise RuntimeError(f"tenant authority failed ({exc.code})") from exc
|
||||
raise self._redacted(exc) from exc
|
||||
except URLError as exc:
|
||||
raise RuntimeError("tenant authority unavailable") from exc
|
||||
return TenantProvisioningResult(
|
||||
|
|
|
|||
|
|
@ -63,11 +63,22 @@ class TenantManagementAdapterTests(unittest.TestCase):
|
|||
"tenant_id": "tenant:friendly:new",
|
||||
"identifier": "tenant:friendly:new",
|
||||
"actor": "user-engine",
|
||||
"display_name": "New",
|
||||
"correlation_id": "corr-1",
|
||||
})
|
||||
self.assertEqual(result.status, "created")
|
||||
self.assertEqual(result.external_ref, "tenant:friendly:new")
|
||||
|
||||
|
||||
def test_create_denial_is_not_reported_as_provisioning_outage(self):
|
||||
adapter = HTTPTenantManagementAdapter(base_url="http://tenant-engine", bearer_token="synthetic")
|
||||
error = _http_error(403, {"error_code": "write_denied", "detail": "private policy detail"})
|
||||
with patch("user_engine.adapters.tenant_management.urlopen", side_effect=error):
|
||||
with self.assertRaises(AuthorizationDenied) as caught:
|
||||
adapter.create_tenant(tenant="tenant:trial:demo-company", display_name="Demo",
|
||||
idempotency_key="demo-create", correlation_id="corr-demo")
|
||||
self.assertNotIn("private policy", str(caught.exception))
|
||||
|
||||
class TenantLifecycleAdapterTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.adapter = HTTPTenantManagementAdapter(
|
||||
|
|
|
|||
|
|
@ -6,6 +6,10 @@ import unittest
|
|||
from dataclasses import replace
|
||||
from datetime import timedelta
|
||||
from urllib.parse import quote, urlencode
|
||||
from urllib.error import HTTPError
|
||||
from unittest.mock import patch
|
||||
|
||||
from user_engine.adapters.tenant_management import HTTPTenantManagementAdapter
|
||||
|
||||
from user_engine.adapters import InMemoryUserEngineStore, LocalAuthorizationCheckPort
|
||||
from user_engine.domain import (
|
||||
|
|
@ -898,6 +902,37 @@ class PortalApplicationTests(unittest.TestCase):
|
|||
)
|
||||
self.assertIn(b"Manage an existing tenant", html)
|
||||
|
||||
def test_platform_tenant_authority_denial_is_redacted_and_creates_no_admin(self):
|
||||
oidc = OIDCClient(
|
||||
issuer="https://kc.example", client_id="portal",
|
||||
redirect_uri="https://users.example/oidc/callback", audience="portal",
|
||||
)
|
||||
oidc.sessions["platform"] = BrowserSession(
|
||||
claims=self.platform_claims(), expires_at=9999999999,
|
||||
csrf_token="platform-csrf",
|
||||
)
|
||||
self.app.oidc_client = oidc
|
||||
self.app.tenant_management = HTTPTenantManagementAdapter(
|
||||
base_url="https://tenants.example", bearer_token="test-service-boundary",
|
||||
)
|
||||
failure = HTTPError(
|
||||
"https://tenants.example/tenants", 403, "Forbidden", {},
|
||||
io.BytesIO(b'{"error_code":"write_denied","detail":"private-policy-detail"}'),
|
||||
)
|
||||
with patch("user_engine.adapters.tenant_management.urlopen", side_effect=failure), \
|
||||
patch.object(self.app.service, "create_user") as create_user:
|
||||
response, payload = invoke(
|
||||
self.app, "/platform/tenants", method="POST",
|
||||
cookie="ue_session=platform", form={
|
||||
"csrf_token": "platform-csrf", "tenant": "tenant:trial:demo-company",
|
||||
"admin_display_name": "First Admin", "admin_email": "admin@example.test",
|
||||
},
|
||||
)
|
||||
self.assertEqual("403 Forbidden", response["status"])
|
||||
self.assertNotIn(b"provisioning_unavailable", payload)
|
||||
self.assertNotIn(b"private-policy-detail", payload)
|
||||
create_user.assert_not_called()
|
||||
|
||||
def test_platform_browser_tenant_and_first_admin_bootstrap(self):
|
||||
claims = self.platform_claims()
|
||||
oidc = OIDCClient(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue