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.
37 lines
1.4 KiB
Python
37 lines
1.4 KiB
Python
import re
|
|
|
|
from django.conf import settings
|
|
from django.shortcuts import redirect
|
|
|
|
|
|
class RBACMiddleware:
|
|
ROLE_ROUTES = {
|
|
"admin": [r"^/admin/", r"^/ops/", r"^/portal/"],
|
|
"ops": [r"^/ops/"],
|
|
"buyer": [r"^/portal/"],
|
|
}
|
|
|
|
def __init__(self, get_response):
|
|
self.get_response = get_response
|
|
|
|
def __call__(self, request):
|
|
user = request.user
|
|
if user.is_authenticated and not user.is_staff and not user.is_superuser:
|
|
path = request.path_info
|
|
user_role = getattr(request.user, "role", None)
|
|
allowed = self.ROLE_ROUTES.get(user_role, [])
|
|
if any(re.match(pattern, path) for pattern in allowed):
|
|
return self.get_response(request)
|
|
# The path belongs to a portal this role may not enter. Send them to
|
|
# the role-aware landing view rather than straight into a portal they
|
|
# cannot use. It used to redirect if *any* role's pattern matched the
|
|
# path without belonging to this role, which bounced a buyer off
|
|
# /portal/ itself (the admin patterns include /portal/), and looped
|
|
# with the landing redirect.
|
|
if any(
|
|
re.match(pattern, path)
|
|
for patterns in self.ROLE_ROUTES.values()
|
|
for pattern in patterns
|
|
):
|
|
return redirect(settings.LOGIN_REDIRECT_URL)
|
|
return self.get_response(request)
|