Bind password setup grants to approved company welcome pages
Some checks are pending
CI Smoke / host-smoke (push) Waiting to run
CI Smoke / container-smoke (push) Waiting to run

Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a092fe-13b1-7f12-ac74-7d258af4d79c
This commit is contained in:
tegwick 2026-09-12 02:43:31 +02:00
parent c8ad7a85ea
commit 48a75b1a54
7 changed files with 267 additions and 8 deletions

View file

@ -47,3 +47,38 @@ class PasswordSetupGrantTests(unittest.TestCase):
with self.assertRaisesRegex(ValueError, "12 characters"):
self.grants.consume(token, "too-short")
self.assertTrue(self.grants.valid(token))
class CompanyReturnTests(unittest.TestCase):
def test_return_is_bound_to_grant_and_cannot_be_changed_by_browser(self):
mapping = {"tenant:trial:demo-company": "https://vergabe.example/demo-company/"}
grants = PasswordSetupGrants(public_url="https://kc.example/setup/password",
setter=lambda *args: None, tenant_returns=mapping)
url = grants.issue("recipient", "tenant:trial:demo-company")
token = url.partition("token=")[2]
mapping["tenant:trial:demo-company"] = "https://attacker.example/"
self.assertNotIn("recipient", url)
self.assertNotIn("return", url)
self.assertEqual("https://vergabe.example/demo-company/", grants.consume(token, "test-password-long"))
with self.assertRaises(ValueError):
grants.consume(token, "test-password-long")
def test_unknown_tenant_has_no_return_and_bad_targets_fail(self):
for target in ("http://example.test/", "https://example.test/?next=evil",
"https://example.test/#fragment", "https://user:password@example.test/"):
with self.assertRaises(ValueError):
PasswordSetupGrants(public_url="https://kc.example/setup/password",
setter=lambda *args: None, tenant_returns={"tenant:trial:demo": target})
grants = PasswordSetupGrants(public_url="https://kc.example/setup/password", setter=lambda *args: None)
token = grants.issue("recipient", "tenant:unknown").partition("token=")[2]
self.assertEqual("", grants.consume(token, "test-password-long"))
def test_expiry_and_failure_never_release_a_return(self):
clock = [0]
grants = PasswordSetupGrants(public_url="https://kc.example/setup/password",
setter=lambda *args: None, clock=lambda: clock[0], ttl_seconds=1,
tenant_returns={"tenant:trial:demo": "https://app.example/demo/"})
token = grants.issue("recipient", "tenant:trial:demo").partition("token=")[2]
clock[0] = 2
with self.assertRaises(ValueError):
grants.consume(token, "test-password-long")