""" Portal SSO middleware for DigiServer v2. When the umbrella nginx verifies the portal JWT it sets two headers: X-Auth-Username — the portal username X-Auth-Role — 'admin' | 'advanced' | 'standard' Portal role → DigiServer local role mapping: admin → admin (full access including user management) advanced → editor (manage content/playlists, no user management) standard → viewer (read-only) This before_request handler reads those headers and auto-logs in the corresponding local DigiServer user, creating them on first access if needed. The local session is then maintained normally by Flask-Login. """ import secrets from flask import request from flask_login import login_user, current_user def init_portal_sso(app): """Register the SSO before_request handler on the given Flask app.""" @app.before_request def _portal_sso(): if current_user.is_authenticated: return username = request.headers.get('X-Auth-Username', '').strip() if not username: return role = request.headers.get('X-Auth-Role', 'user').strip() user = _get_or_create_user(username, role) if user: login_user(user, remember=False) def _portal_role_to_local(portal_role): """Map a portal role string to the DigiServer local role.""" if portal_role == 'admin': return 'admin' if portal_role == 'advanced': return 'editor' return 'viewer' # 'standard' or anything unknown def _get_or_create_user(username, role): from app.models.user import User from app.extensions import db, bcrypt try: target_role = _portal_role_to_local(role) user = User.query.filter_by(username=username).first() if not user: hashed_pw = bcrypt.generate_password_hash(secrets.token_hex(32)).decode('utf-8') user = User( username=username, password=hashed_pw, role=target_role, ) db.session.add(user) db.session.commit() elif user.role != target_role: # Role changed in portal → sync it here immediately user.role = target_role db.session.commit() return user except Exception: return None