134 lines
7 KiB
Python
134 lines
7 KiB
Python
|
|
"""Login state, active sign-in, and allowed memberships stay separate."""
|
||
|
|
import unittest
|
||
|
|
|
||
|
|
from test_web import invoke
|
||
|
|
from user_engine.domain import Membership
|
||
|
|
from user_engine.oidc import BrowserSession
|
||
|
|
from user_engine.testing.fixtures import human_actor_claims
|
||
|
|
|
||
|
|
import test_portal_navigation
|
||
|
|
|
||
|
|
|
||
|
|
def _section(body: bytes, element_id: str) -> bytes:
|
||
|
|
marker = f'id="{element_id}"'.encode()
|
||
|
|
start = body.index(marker)
|
||
|
|
end = body.index(b"</ul>", start)
|
||
|
|
return body[start:end]
|
||
|
|
|
||
|
|
|
||
|
|
class AccountAwarenessTests(unittest.TestCase):
|
||
|
|
setUp = test_portal_navigation.PortalNavigationTests.setUp
|
||
|
|
get = test_portal_navigation.PortalNavigationTests.get
|
||
|
|
|
||
|
|
def test_signed_out_home_states_only_the_portal_session(self):
|
||
|
|
_, body = invoke(self.app, "/", query="username=forged&tenant=tenant:evil:one")
|
||
|
|
self.assertIn(b"Login state", body)
|
||
|
|
self.assertIn(b"You are not signed in to this portal.", body)
|
||
|
|
self.assertNotIn(b"Active now", body)
|
||
|
|
self.assertNotIn(b"Allowed tenants", body)
|
||
|
|
self.assertNotIn(b"forged", body)
|
||
|
|
self.assertNotIn(b"tenant:evil:one", body)
|
||
|
|
|
||
|
|
def test_token_tenant_without_membership_is_active_and_not_allowed(self):
|
||
|
|
session = self.app.service.me(self.oidc.claims("member"), correlation_id="synthetic")
|
||
|
|
self.assertIsNotNone(
|
||
|
|
self.app.service.store.tenant_account("tenant:trial:demo-company", session.user.user_id)
|
||
|
|
)
|
||
|
|
_, body = self.get("/onboarding", who="member")
|
||
|
|
active = _section(body, "active-tenant-list")
|
||
|
|
allowed = _section(body, "allowed-tenant-list")
|
||
|
|
self.assertIn(b"<strong>tenant:trial:demo-company</strong> - Active", active)
|
||
|
|
self.assertNotIn(b"tenant:two", active)
|
||
|
|
self.assertIn(b"No tenant memberships are recorded.", allowed)
|
||
|
|
self.assertNotIn(b"tenant:trial:demo-company", allowed)
|
||
|
|
self.assertIn(b"No workload access is recorded.", body)
|
||
|
|
self.assertIn(b"Workload decisions are not checked.", body)
|
||
|
|
self.assertNotIn(b"Viewing", body)
|
||
|
|
self.assertIn(b"An ordinary sign-in uses one tenant.", body)
|
||
|
|
self.assertIn(b"This is the portal session.", body)
|
||
|
|
|
||
|
|
def test_allowed_tenant_that_is_not_active_uses_sign_in(self):
|
||
|
|
session = self.app.service.me(self.oidc.claims("member"), correlation_id="synthetic")
|
||
|
|
self.app.service.store.save_membership(Membership(
|
||
|
|
membership_id="mem-other", user_id=session.user.user_id,
|
||
|
|
tenant="tenant:other:company", scope_type="tenant",
|
||
|
|
scope_id="tenant:other:company", kind="user",
|
||
|
|
))
|
||
|
|
_, body = self.get("/onboarding", who="member")
|
||
|
|
allowed = _section(body, "allowed-tenant-list")
|
||
|
|
active = _section(body, "active-tenant-list")
|
||
|
|
self.assertIn(b"tenant:other:company - user - Inactive.", allowed)
|
||
|
|
self.assertIn(b'href="/login?tenant_hint=tenant%3Aother%3Acompany"', allowed)
|
||
|
|
self.assertNotIn(b"<form", allowed)
|
||
|
|
self.assertIn(b"tenant:trial:demo-company", active)
|
||
|
|
self.assertNotIn(b"tenant:other:company", active)
|
||
|
|
self.assertIn(b"does not end a session an application already has.", body)
|
||
|
|
|
||
|
|
def test_recorded_workload_stays_allowed_and_unchecked(self):
|
||
|
|
session = self.app.service.me(self.oidc.claims("member"), correlation_id="synthetic")
|
||
|
|
self.app.service.store.save_membership(Membership(
|
||
|
|
membership_id="mem-work", user_id=session.user.user_id,
|
||
|
|
tenant="tenant:trial:demo-company", scope_type="service",
|
||
|
|
scope_id="vergabe-demo-company", kind="user",
|
||
|
|
))
|
||
|
|
_, body = self.get("/onboarding", who="member")
|
||
|
|
workloads = _section(body, "allowed-workload-list")
|
||
|
|
allowed_tenants = _section(body, "allowed-tenant-list")
|
||
|
|
self.assertIn(b"vergabe-demo-company - user (tenant:trial:demo-company) - Allowed, recorded here", workloads)
|
||
|
|
self.assertIn(b"Workload decisions are not checked.", body)
|
||
|
|
self.assertIn(b"No tenant memberships are recorded.", allowed_tenants)
|
||
|
|
|
||
|
|
def test_ordinary_sign_in_ignores_a_second_active_tenant_claim(self):
|
||
|
|
self.oidc.sessions["member"].claims["active_tenants"] = [
|
||
|
|
"tenant:trial:demo-company", "tenant:two:beta",
|
||
|
|
]
|
||
|
|
_, body = self.get("/onboarding", who="member")
|
||
|
|
active = _section(body, "active-tenant-list")
|
||
|
|
self.assertIn(b"tenant:trial:demo-company", active)
|
||
|
|
self.assertNotIn(b"tenant:two:beta", active)
|
||
|
|
|
||
|
|
def test_exception_role_shows_every_tenant_the_sign_in_lists(self):
|
||
|
|
for role, kind in [("tenant-admin", "user"), ("platform-root", "user"), ("user", "vendor"), ("user", "multi-hire")]:
|
||
|
|
with self.subTest(role=role, kind=kind):
|
||
|
|
subject = f"{role}-{kind}"
|
||
|
|
claims = human_actor_claims(subject=subject, tenant="tenant:one:alpha")
|
||
|
|
claims["roles"] = [role]
|
||
|
|
claims["active_tenants"] = ["tenant:one:alpha", "tenant:two:beta"]
|
||
|
|
claims["preferred_username"] = subject
|
||
|
|
self.oidc.sessions[subject] = BrowserSession(claims, 9999999999, subject + "-csrf")
|
||
|
|
session = self.app.service.me(claims, correlation_id="synthetic")
|
||
|
|
if kind in {"vendor", "multi-hire"}:
|
||
|
|
self.app.service.store.save_membership(Membership(
|
||
|
|
membership_id="mem-" + subject, user_id=session.user.user_id,
|
||
|
|
tenant="tenant:one:alpha", scope_type="tenant",
|
||
|
|
scope_id="tenant:one:alpha", kind=kind,
|
||
|
|
))
|
||
|
|
_, body = self.get("/onboarding", who=subject)
|
||
|
|
active = _section(body, "active-tenant-list")
|
||
|
|
self.assertIn(b"<strong>tenant:one:alpha</strong> - Active", active)
|
||
|
|
self.assertIn(b"<strong>tenant:two:beta</strong> - Active", active)
|
||
|
|
self.assertNotIn(b'href="/login?tenant_hint=tenant%3Atwo', body)
|
||
|
|
|
||
|
|
def test_exception_without_a_second_tenant_claim_stays_on_one(self):
|
||
|
|
claims = human_actor_claims(subject="vendor-one", tenant="tenant:one:alpha")
|
||
|
|
claims["roles"] = ["user"]
|
||
|
|
claims["preferred_username"] = "vendor-one"
|
||
|
|
self.oidc.sessions["vendor-one"] = BrowserSession(claims, 9999999999, "vendor-one-csrf")
|
||
|
|
session = self.app.service.me(claims, correlation_id="synthetic")
|
||
|
|
self.app.service.store.save_membership(Membership(
|
||
|
|
membership_id="mem-vendor-one", user_id=session.user.user_id,
|
||
|
|
tenant="tenant:other:company", scope_type="tenant",
|
||
|
|
scope_id="tenant:other:company", kind="vendor",
|
||
|
|
))
|
||
|
|
_, body = self.get("/onboarding", who="vendor-one")
|
||
|
|
active = _section(body, "active-tenant-list")
|
||
|
|
allowed = _section(body, "allowed-tenant-list")
|
||
|
|
self.assertIn(b"tenant:one:alpha", active)
|
||
|
|
self.assertNotIn(b"tenant:other:company", active)
|
||
|
|
self.assertIn(b"tenant:other:company - vendor - Inactive.", allowed)
|
||
|
|
self.assertIn(b"This sign-in has one active tenant.", body)
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
unittest.main()
|