""" Internal routes — called by the EDP portal (not by browsers). POST /internal/sync-user Called by the portal whenever it grants or updates a user's access to the itassets app. Ensures the local AdminUser record exists and has the correct role before the user ever logs in for the first time. Body (JSON): { "username": "alice", "role": "advanced" } Header: X-Internal-Token: Portal roles are mapped to local roles: admin → admin advanced → editor standard → readonly """ import secrets from flask import Blueprint, request, jsonify, current_app from app.extensions import db from app.models.admin_user import AdminUser from app.utils.portal_sso import _portal_role_to_local bp = Blueprint('internal', __name__, url_prefix='/internal') def _check_token(): expected = current_app.config.get('INTERNAL_SYNC_SECRET', '') provided = request.headers.get('X-Internal-Token', '') # Use hmac.compare_digest equivalent via secrets.compare_digest if not expected or not secrets.compare_digest(expected, provided): return False return True @bp.route('/sync-user', methods=['POST']) def sync_user(): if not _check_token(): return jsonify({'error': 'Unauthorized'}), 401 data = request.get_json(silent=True) or {} username = (data.get('username') or '').strip() portal_role = (data.get('role') or 'standard').strip() if not username: return jsonify({'error': 'username is required'}), 400 local_role = _portal_role_to_local(portal_role) try: user = AdminUser.query.filter_by(username=username).first() if user: if user.role != local_role: user.role = local_role db.session.commit() status = 'updated' else: user = AdminUser( username=username, email=f'{username}@portal.local', full_name=username, role=local_role, is_active=True, ) user.set_password(secrets.token_hex(32)) # random unusable password db.session.add(user) db.session.commit() status = 'created' return jsonify({'status': status, 'username': username, 'role': local_role}), 200 except Exception as exc: current_app.logger.error('sync-user failed: %s', exc) return jsonify({'error': str(exc)}), 500