Proyecto de Modernización Tecnológica Municipal

Unificación del Portal Ciudadano con Identidad Digital Única

Se integró exitosamente el Portal Ciudadano con la plataforma central de Authentik. Ahora los vecinos de Pergamino cuentan con un único inicio de sesión seguro para todos los servicios del Municipio, preservando automáticamente toda su información histórica, trámites, inmuebles y vehículos registrados.

Portal Ciudadano
Vecinos Incorporados
31.869
Base completa migrada
Registros Duplicados
0
Fusión automática por CUIT
Llave Digital Única
1 Solo Login
Portal, Reclamos y Trámites
Seguridad de Claves
100% Cifrado
Protección bancaria PBKDF2

1. ¿Cuál era el objetivo del proyecto?

Históricamente, el Portal Ciudadano funcionaba como una isla con su propio sistema de contraseñas. Cada vez que el vecino ingresaba debía recordar credenciales distintas a las de otros sistemas municipales.

Antes
  • Múltiples contraseñas dispersas en distintas plataformas.
  • Contraseñas guardadas en la base de datos sin cifrado moderno.
  • Sin posibilidad de inicio de sesión unificado municipal (SSO).
Ahora con Authentik
  • Un solo usuario y contraseña para todos los servicios digitales del Municipio.
  • Cifrado criptográfico automático de contraseñas de alta seguridad.
  • Los vecinos conservan intactos sus inmuebles, rodados, boletas e historial.

2. ¿Cómo se realizó la integración? (Paso a Paso)

Paso 1
Incorporación y Cifrado de Ciudadanos

Se procesó la base histórica municipal (31.869 ciudadanos) cargándolos en una carpeta virtual dedicada llamada "Ciudadanos" en Authentik. De este modo, los vecinos quedan completamente organizados e independientes de las cuentas de empleados municipales. Además, sus contraseñas fueron automáticamente protegidas con cifrado seguro.

Paso 2
Conexión del Portal con Authentik

Se configuró el Portal Ciudadano para comunicarse directamente con Authentik utilizando el estándar internacional de identidad digital OpenID Connect (OIDC). El vecino solo presiona un botón y Authentik valida de forma segura quién es.

Paso 3
Reconocimiento Inteligente (Anti-Duplicación)

Cuando el ciudadano entra por primera vez con Authentik, el portal no crea un usuario duplicado. Busca de forma inteligente su CUIT, DNI o correo en la base histórica y enlaza su sesión con su cuenta existente. Así, el vecino no pierde ninguna boleta ni trámite anterior.

Paso 4
Cierre de Sesión Completo y Seguro

Al tocar "Cerrar sesión" en cualquier pantalla, se cierran tanto el portal como la sesión central de Authentik al mismo tiempo. Esto garantiza total privacidad y protección al usar computadoras compartidas o cabinas públicas.

3. Demostración en Vivo: Cómo Probar el Sistema

Cualquier autoridad o miembro del equipo puede verificar el funcionamiento ahora mismo desde su navegador:

Caso 1: Ciudadano con Perfil Activo
Acceso Directo

Inicia sesión e ingresa directamente al panel principal del vecino con sus datos vinculados:

USUARIO / CUIT: 20352255433
CONTRASEÑA: 1234567
Vecino: Noguera Juan Diego
Probar este Usuario
Caso 2: Ciudadano con Datos a Completar
Validación de Perfil

Inicia sesión y el sistema detecta que falta su domicilio, redirigiéndolo a completar perfil:

USUARIO / CUIT: 23235886464
CONTRASEÑA: sistemas
Vecina: Etchart Maria Brigida • DNI: 23588646
Probar este Usuario
Guía rápida de comprobación:
  1. Hacé clic en "Probar este Usuario" o ingresá a http://192.168.10.154:8081.
  2. Presioná el botón azul "Iniciar sesión con Authentik" e ingresá las credenciales indicadas arriba.
  3. Verificá que el portal reconozca de inmediato al vecino y cargue su información.
  4. Hacé clic en "Cerrar sesión" en la barra superior para comprobar que la sesión se desactiva por completo en ambos sistemas.

4. Próxima Etapa: Integración con ARCA (AFIP) y Mi Argentina

Autenticación de Nivel 2 y 3 sin delegación de servicios ni fricción para el vecino
Innovación de Identidad Federal

Una de las preguntas más frecuentes es si el vecino tiene que entrar al complejo "Administrador de Relaciones" de AFIP a adherir el servicio municipal. La respuesta es NO. Con Authentik actuando como Federador de Identidad (Identity Broker), el vecino únicamente ingresa su CUIT y Clave Fiscal en ARCA, y el sistema municipal recibe automáticamente su nivel de seguridad validado.

Simulador Interactivo del Recorrido de Credenciales
1. Vecino
Clic "Login ARCA"
2. Portal Municipal
Despacha OIDC
3. ARCA (AFIP)
Valida Clave Fiscal
4. Authentik SSO
Mapea Identidad
5. Trámite Habilitado
Nivel 2 Verificado
Paso 0 de 5
Simulador en espera

Presioná el botón "Simular ARCA (Nivel 2)" o "Simular Mi Argentina" arriba para ver cómo viajan los datos y cómo el portal valida los trámites sensibles de forma transparente.

// Datos de la transacción de identidad digital { "estado": "ESPERANDO_INICIO", "origen": "Portal Ciudadano Pergamino", "nivel_seguridad": null, "tramite_sensible": "BLOQUEADO" }
Cero Fricción para el Vecino

El ciudadano no tiene que delegar servicios ni ingresar al Administrador de Relaciones de AFIP. Solo pone su CUIT y Clave Fiscal en la web oficial de ARCA.

Trámites con Nivel 2 o 3

ARCA devuelve a Authentik el campo nivel_seguridad: 2. El portal lo recibe y habilita automáticamente gestiones de alto impacto (débito automático, exenciones y libre deudas).

Trámite Único Municipal

El convenio de integración se tramita una sola vez entre el Municipio y ARCA. Una vez habilitado, todos los contribuyentes del país pueden usarlo sin pasos previos.

5. Documentación Técnica para el Área de Desarrollo

Arquitectura, archivos creados/modificados y flujo OpenID Connect (OIDC)
Para Equipo TI / Devs
Archivos Modificados y Creados en el Portal
Archivo Tipo Descripción Técnica y Rol en el SSO
authentik_login.php Nuevo Genera el token criptográfico anti-CSRF (state) en la sesión PHP y redirige al navegador del ciudadano al endpoint de autorización de Authentik (/application/o/authorize/) solicitando los scopes openid profile email.
authentik_callback.php Nuevo Receptor central del flujo OIDC: Valida el parámetro state, intercambia el code por el access_token vía cURL POST contra /application/o/token/, consulta el endpoint /application/o/userinfo/ y ejecuta el algoritmo de fusión anti-duplicación (busca por CUIT $\to$ DNI $\to$ Email para asociar el id_usuario histórico). Inicializa las variables de sesión que el portal requiere ($_SESSION['tokenmuni'], $_SESSION['username']) y redirige a portal.php.
cerrar_sesion.php Modificado Single Logout (SLO): Destruye la sesión PHP local, elimina la cookie PHPSESSID y redirige al navegador al flujo de invalidación de Authentik (/if/flow/portal-ciudadano-logout-flow/). Authentik desautentica la cookie de SSO y retorna al usuario a index.php limpio.
conexion.php Modificado Parametrización dinámica por variables de entorno Docker (DB_HOST, DB_USER, etc.) y desactivación del modo estricto de excepciones de MySQLi (mysqli_report(MYSQLI_REPORT_OFF)) necesario para que el código PHP 7 legado ejecute en PHP 8.1 sin fallas fatales.
portal.php Modificado Protección y control de conexiones secundarias (bases no migradas como turnos y deportes) para evitar que conexiones fallidas interrumpan la carga del panel del vecino.
index.php Modificado Incorporación del botón oficial "Iniciar sesión con Authentik" integrado con la estética municipal.
71 archivos PHP Limpieza BOM Remoción de la marca de orden de bytes UTF-8 (\xef\xbb\xbf) que provocaba que se emitiera salida previa a session_start(), bloqueando el envío de cookies de sesión.
Estructura del Código Implementado
authentik_callback.php • Algoritmo de Búsqueda y Fusión de Identidad PHP
// 1. Extraer datos de UserInfo devueltos por Authentik
$cuit = $attributes['cuit'] ?? ($user_info['preferred_username'] ?? '');
$dni  = $attributes['dni'] ?? '';
$mail = $user_info['email'] ?? '';

// 2. BÚSQUEDA JERÁRQUICA: Evitar duplicar registros en tabla usuarios
$usuario_encontrado = null;

// Criterio 1: Búsqueda por CUIT o Usuario
if (!empty($cuit)) {
    $stmt = $conn->prepare("SELECT * FROM usuarios WHERE cuit = ? OR usuario = ? LIMIT 1");
    $stmt->bind_param("ss", $cuit, $cuit);
    $stmt->execute();
    $res = $stmt->get_result();
    if ($res->num_rows > 0) $usuario_encontrado = $res->fetch_assoc();
}

// Criterio 2: Fallback por DNI si no se encontró por CUIT
if (!$usuario_encontrado && !empty($dni)) {
    $stmt = $conn->prepare("SELECT * FROM usuarios WHERE dni = ? LIMIT 1");
    $stmt->bind_param("s", $dni);
    $stmt->execute();
    $res = $stmt->get_result();
    if ($res->num_rows > 0) $usuario_encontrado = $res->fetch_assoc();
}

// 3. FUSIÓN O ALTA
$token_sesion = bin2hex(random_bytes(32));
if ($usuario_encontrado) {
    // REUTILIZAR id_usuario HISTÓRICO: conserva sus inmuebles, autos y pagos
    $stmt_up = $conn->prepare("UPDATE usuarios SET token = ?, activo = 1, fechaum = CURDATE() WHERE id_usuario = ?");
    $stmt_up->bind_param("si", $token_sesion, $usuario_encontrado['id_usuario']);
    $stmt_up->execute();
    $_SESSION['username']  = $usuario_encontrado['usuario'];
    $_SESSION['tokenmuni'] = $token_sesion;
} else {
    // USUARIO NUEVO: dar de alta con atributos de Authentik
    // ... INSERT INTO usuarios ...
}
header('Location: portal.php');
exit();
authentik_login.php • Despacho hacia Authentik Authorization Endpoint PHP
session_start();

// 1. Generar state criptográfico anti-CSRF y almacenar en sesión local
$state = bin2hex(random_bytes(16));
$_SESSION['oauth_state'] = $state;

// 2. Parámetros estándar OpenID Connect
$client_id     = 'portal-ciudadano-legacy';
$redirect_uri  = 'http://192.168.10.154:8081/authentik_callback.php';
$scope         = 'openid profile email';

$auth_url = 'http://192.168.10.154:9000/application/o/authorize/?' . http_build_query([
    'response_type' => 'code',
    'client_id'     => $client_id,
    'redirect_uri'  => $redirect_uri,
    'scope'         => $scope,
    'state'         => $state
]);

header('Location: ' . $auth_url);
exit();
cerrar_sesion.php • Cierre de Sesión Unificado (Single Logout) PHP
session_start();

// 1. Destruir sesión PHP y expirar cookie local
$_SESSION = array();
if (ini_get("session.use_cookies")) {
    $params = session_get_cookie_params();
    setcookie(session_name(), '', time() - 42000,
        $params["path"], $params["domain"],
        $params["secure"], $params["httponly"]
    );
}
session_unset();
session_destroy();

// 2. Redirigir al flujo de invalidación de Authentik para desautenticar la sesión SSO
$authentik_base_url = 'http://192.168.10.154:9000';
$logout_url = rtrim($authentik_base_url, '/') . '/if/flow/portal-ciudadano-logout-flow/';

header("Location: " . $logout_url);
exit();

6. Guía para Integrar Nuevos Sistemas Municipales a Authentik SSO

Protocolo estandarizado paso a paso para cualquier lenguaje (PHP, Node, Python, .NET)

Cualquier nuevo desarrollo o sistema municipal existente puede sumarse a la plataforma de identidad única Authentik siguiendo estos 4 pasos estandarizados:

Paso 1
Dar de alta el Proveedor en Authentik
  • Ingresar al Administrador de Authentik $\to$ Applications $\to$ Providers.
  • Crear un OAuth2/OpenID Provider.
  • Authorization flow: Elegir implicit-consent (evita pantallas de confirmación redundantes).
  • Invalidation flow: Asociar el flujo de logout municipal (portal-ciudadano-logout-flow).
  • Redirect URIs: Registrar las URLs de callback autorizadas y las URLs de post-logout.
Paso 2
Asignar Scopes y Atributos
  • En Property Mappings del Provider, incluir:
    • openid, email, profile.
    • Portal Ciudadano Attributes: Este mapping entrega directamente en el endpoint UserInfo el CUIT, DNI, domicilio y teléfono del vecino.
  • Crear la Application en Authentik vinculando el Provider creado.
Paso 3
Implementar el Flujo OIDC en la Aplicación
  • Ruta Login: Redirigir a http://192.168.10.154:9000/application/o/authorize/ con client_id, redirect_uri y state.
  • Ruta Callback: Recibir el code y pedir el token haciendo POST a http://192.168.10.154:9000/application/o/token/.
  • UserInfo: Con el token, consultar http://192.168.10.154:9000/application/o/userinfo/ para extraer la identidad del ciudadano.
Paso 4
Sincronizar el Cierre de Sesión (SLO)
  • Al hacer logout en el sistema, destruir la sesión o JWT local.
  • Redirigir al flujo de logout de Authentik: http://192.168.10.154:9000/if/flow/portal-ciudadano-logout-flow/.
  • Authentik limpiará la sesión central y devolverá al usuario a la URL de inicio configurada.
Buena Práctica para Base de Datos Locales:

Nunca utilices el correo electrónico como clave primaria para vincular ciudadanos; utiliza siempre el CUIT (que viene en preferred_username o en attributes.cuit). El CUIT es único, inmutable y garantiza que ningún trámite se desvincule aunque el vecino cambie de email.

Portal Ciudadano Operativo

El sistema se encuentra 100% desplegado y validado en el servidor municipal listo para su uso institucional.