"""Session establishment after verified identity claims.""" from __future__ import annotations from django.conf import settings from django.contrib.auth import login from django.http import HttpRequest from django.utils import timezone from coulomb_social.apps.members.models import Member, User from .user_engine import IdentityClaims, get_user_engine_client def establish_session(request: HttpRequest, claims: IdentityClaims) -> Member: """Link platform identity → Member, log Django user in. No passwords.""" tenant_id = claims.tenant or settings.DEFAULT_TENANT_ID application_id = settings.USER_ENGINE_APPLICATION_ID link = get_user_engine_client().link_or_create( claims, tenant_id=tenant_id, application_id=application_id ) member = Member.objects.filter(issuer=claims.issuer, subject=claims.subject).first() display = ( link.display_name or claims.name or claims.preferred_username or claims.email or claims.subject ) email = link.email or claims.email or "" username = f"{claims.subject}@{_issuer_slug(claims.issuer)}"[:255] if member is None: user = User.objects.create_user( username=username, email=email, full_name=display, ) member = Member.objects.create( tenant_id=tenant_id, user=user, user_engine_user_id=link.user_id, issuer=claims.issuer, subject=claims.subject, display_name=display, email=email, ) else: user = member.user user.email = email or user.email user.full_name = display or user.full_name user.save(update_fields=["email", "full_name"]) member.display_name = display member.email = email or member.email member.user_engine_user_id = link.user_id member.tenant_id = tenant_id member.last_login_at = timezone.now() member.save() # Stash non-secret claim provenance for account diagnostics (T07) request.session["user_engine_source"] = link.source request.session["user_engine_user_id"] = link.user_id request.session["identity_groups"] = list(claims.groups) request.session["identity_roles"] = list(claims.roles) request.session["identity_principal_type"] = claims.principal_type or "human" request.session["identity_assurance"] = dict(claims.assurance or {}) login(request, user, backend="django.contrib.auth.backends.ModelBackend") return member def _issuer_slug(issuer: str) -> str: return ( issuer.replace("https://", "") .replace("http://", "") .replace("/", "_") .replace(":", "_")[:64] or "issuer" )