""" control/panel/auth.py --------------------- Superadmin authentication for the control panel (MT-4). Uses Flask session directly (no Flask-Login) — the panel is a standalone app with no dependency on the main app's login_manager. Session key: 'sa_id' (superadmin.id when logged in) """ import logging from flask import ( Blueprint, render_template, redirect, url_for, request, session, flash, ) from control.base import control_session from control.models import Superadmin, TenantAudit from control.time_utils import now_eastern logger = logging.getLogger(__name__) bp = Blueprint('auth', __name__) def _log_audit(action, superadmin_id=None, tenant_id=None, details=None): """Write a TenantAudit row for superadmin actions.""" try: ip = (request.headers.get('X-Forwarded-For', '').split(',')[0].strip() or request.remote_addr) with control_session() as s: s.add(TenantAudit( superadmin_id=superadmin_id, action=action[:50], tenant_id=tenant_id, details=details, ip_address=(ip or '')[:45], created_at=now_eastern(), )) except Exception as exc: logger.error('TenantAudit write failed: %s', exc) # ── Login ───────────────────────────────────────────────────────────────────── @bp.route('/login', methods=['GET', 'POST']) def login(): if session.get('sa_id'): return redirect(url_for('tenants.list_tenants')) error = None if request.method == 'POST': username = (request.form.get('username') or '').strip() password = request.form.get('password') or '' with control_session() as s: sa = s.query(Superadmin).filter_by(username=username, active=True).first() if sa and sa.check_password(password): session.permanent = True session['sa_id'] = sa.id session['sa_username'] = sa.username logger.info('PANEL | login | superadmin=%s', username) _log_audit('LOGIN', superadmin_id=sa.id, details=f'superadmin={username}') flash(f'Welcome, {sa.username}!', 'success') next_url = request.args.get('next') or url_for('tenants.list_tenants') return redirect(next_url) else: logger.warning('PANEL | login_fail | username=%s', username) error = 'Invalid credentials.' return render_template('panel/login.html', error=error) # ── Logout ──────────────────────────────────────────────────────────────────── @bp.route('/logout') def logout(): sa_id = session.get('sa_id') sa_name = session.get('sa_username', '?') session.clear() logger.info('PANEL | logout | superadmin=%s', sa_name) if sa_id: _log_audit('LOGOUT', superadmin_id=sa_id, details=f'superadmin={sa_name}') flash('Logged out.', 'info') return redirect(url_for('auth.login'))