Jun 27 MT-4
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
"""
|
||||
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'))
|
||||
Reference in New Issue
Block a user