ixg_platform/apps/users/tests.py
ixgadmin 19d67555da Add public buyer self-registration
A UK buyer can now create their own account at /portal/signup/. The screen
creates a Keycloak user through a least-privilege service account
(ixg-provisioning: manage-users, view-users) and the matching Django row as
a buyer, then sends them through the normal sign-in flow to the portal.

Staff status is derived from the role in the OIDC backend rather than
asserted, so a self-registered buyer is not staff and does not become staff
on a later sign-in. The platform root and the RBAC middleware now route
each role to its own portal, which also fixes a redirect loop that the
staff fix exposed for non-staff buyers.
2026-09-21 11:30:29 +00:00

107 lines
4.3 KiB
Python

"""Staff status is derived from the role, never asserted.
The bug these pin: ``create_user`` and ``update_user`` used to set
``is_staff=True`` on every account, so a self-registered buyer came out as staff
— and, because ``update_user`` runs on every sign-in, a buyer row created
correctly would still flip to staff the first time they signed in. The second
case is the one that passes a first test and fails later, so it is covered
directly.
"""
from django.contrib.auth import get_user_model
from django.test import TestCase
from .auth import KeycloakOIDCBackend, is_staff_for_role
from .keycloak import _split_name
User = get_user_model()
class SplitNameTests(TestCase):
"""Both Keycloak name fields must be non-empty, or sign-in shows the
"Update Account Information" (VERIFY_PROFILE) step."""
def test_a_two_part_name_splits(self):
self.assertEqual(_split_name("Ada Greenfield"), ("Ada", "Greenfield"))
def test_a_multi_part_name_keeps_the_last_word_as_the_surname(self):
self.assertEqual(_split_name("Ada Mary Greenfield"), ("Ada Mary", "Greenfield"))
def test_a_single_word_name_fills_both_fields(self):
self.assertEqual(_split_name("Ada"), ("Ada", "Ada"))
def test_an_empty_name_yields_empty_fields(self):
self.assertEqual(_split_name(" "), ("", ""))
class StaffRoleTests(TestCase):
def setUp(self):
self.backend = KeycloakOIDCBackend()
def test_only_ops_and_admin_are_staff(self):
self.assertFalse(is_staff_for_role("buyer"))
self.assertTrue(is_staff_for_role("ops"))
self.assertTrue(is_staff_for_role("admin"))
self.assertTrue(is_staff_for_role("buyer", is_superuser=True))
def test_create_user_derives_staff_from_the_claims_role(self):
buyer = self.backend.create_user(
{"email": "signup-buyer@example.com", "name": "Buyer One", "sub": "sub-buyer", "role": "buyer"}
)
self.assertEqual(buyer.role, "buyer")
self.assertFalse(buyer.is_staff)
ops = self.backend.create_user(
{"email": "signup-ops@example.com", "name": "Ops One", "sub": "sub-ops", "role": "ops"}
)
self.assertTrue(ops.is_staff)
def test_create_user_defaults_to_buyer_without_a_role_claim(self):
user = self.backend.create_user(
{"email": "signup-norole@example.com", "name": "No Role", "sub": "sub-norole"}
)
self.assertEqual(user.role, "buyer")
self.assertFalse(user.is_staff)
def test_update_user_does_not_staff_a_buyer(self):
user = User.objects.create_user(
email="buyer-stays@example.com", role="buyer", is_staff=False, keycloak_id="sub-1"
)
self.backend.update_user(
user, {"email": "buyer-stays@example.com", "name": "Buyer", "sub": "sub-1", "role": "buyer"}
)
user.refresh_from_db()
self.assertEqual(user.role, "buyer")
self.assertFalse(user.is_staff)
def test_update_user_staffs_ops_and_admin(self):
for role in ("ops", "admin"):
user = User.objects.create_user(
email=f"{role}-signin@example.com", role="buyer", is_staff=False,
keycloak_id=f"sub-{role}",
)
self.backend.update_user(
user, {"email": user.email, "name": role, "sub": user.keycloak_id, "role": role}
)
user.refresh_from_db()
self.assertEqual(user.role, role)
self.assertTrue(user.is_staff)
def test_update_user_keeps_the_existing_role_when_the_claim_is_absent(self):
user = User.objects.create_user(
email="ops-no-role-claim@example.com", role="ops", is_staff=True, keycloak_id="sub-2"
)
self.backend.update_user(user, {"email": user.email, "name": "Ops", "sub": "sub-2"})
user.refresh_from_db()
self.assertEqual(user.role, "ops")
self.assertTrue(user.is_staff)
def test_update_user_preserves_a_superuser(self):
user = User.objects.create_superuser(
email="super@example.com", password="pass1234", role="buyer", keycloak_id="sub-3"
)
self.backend.update_user(
user, {"email": user.email, "name": "Super", "sub": "sub-3", "role": "buyer"}
)
user.refresh_from_db()
self.assertTrue(user.is_superuser)
self.assertTrue(user.is_staff)