Skip to content

Gestión de contraseñas

Configura en Potato el hash de contraseñas con PBKDF2-SHA256, el restablecimiento desde la CLI y la API de administración, los enlaces de restablecimiento con token de autoservicio y el almacenamiento de credenciales en SQLite o PostgreSQL.

Novedad en la v2.4.0

El sistema de autenticación de Potato usa PBKDF2-SHA256 con 100.000 iteraciones y una sal distinta por usuario, el mismo enfoque que recomienda el NIST para almacenar contraseñas de forma segura. Esta página explica cómo se guardan las contraseñas, cómo restablecerlas y cómo conservar las credenciales entre reinicios del servidor.

Se aplica a los métodos in_memory y database. Con OAuth, la contraseña es cosa del proveedor de identidad, así que nada de esto aplica salvo a las cuentas locales en modo mixto.

Implementación de seguridad

Las contraseñas se guardan en formato salt$hash:

  • Sal hexadecimal de 32 caracteres, única para cada usuario
  • Resumen hexadecimal de 64 caracteres, obtenido con PBKDF2-HMAC-SHA256 sobre la contraseña con esa sal y 100.000 iteraciones
  • Comparación en tiempo constante mediante hmac.compare_digest para evitar ataques de temporización

Una sola pasada de SHA-256 sobre una contraseña con sal es lo bastante rápida como para atacarla por fuerza bruta a gran escala. Las 100.000 iteraciones son lo que encarece cada intento.

Las contraseñas en texto plano que ya existan en archivos user_config.json se vuelven a hashear automáticamente con sales únicas cuando Potato las carga, sin necesidad de ninguna migración manual.

Configuración predeterminada

De forma predeterminada, Potato usa autenticación en memoria. require_password es una clave de nivel superior y no forma parte del bloque authentication:

yaml
require_password: true
 
authentication:
  method: in_memory
 
user_config:
  users:
    - username: "annotator1"
      password: "initial-password"   # will be hashed on first load
    - username: "annotator2"
      password: "initial-password"

Credenciales persistentes

Las cuentas creadas mediante el formulario de registro se escriben en un archivo JSONL y se vuelven a leer en el siguiente arranque. Con in_memory, ese archivo es user_config.json, junto al directorio de salida, salvo que indiques otro.

Persistencia en archivo

yaml
authentication:
  method: in_memory
  user_config_path: /shared/path/to/user_config.jsonl

Indica una ruta cuando varias instancias del servidor comparten una misma lista de usuarios, o cuando quieres guardar la lista en un lugar distinto al de las anotaciones. Los registros nuevos y los cambios de contraseña se escriben en el momento en que ocurren.

Guarda la lista de usuarios junto con la salida de anotación. El directorio de cada anotador lleva su nombre de usuario, así que si la lista se pierde pero el directorio de salida se conserva, la siguiente persona que escriba ese nombre de usuario heredaría el trabajo de otra. Potato rechaza el registro en ese caso, lo que significa que el anotador no puede volver a entrar hasta que restaures el archivo.

Antes de la v2.8.3, in_memory no escribía nada salvo que user_config_path estuviera definido explícitamente, así que las cuentas no sobrevivían a un reinicio. Si ejecutaste un estudio con una versión anterior, esas cuentas se han perdido; las anotaciones no.

Backend de base de datos

SQLite (sin dependencias adicionales):

yaml
authentication:
  method: database
  database_url: "sqlite:///auth/users.db"

PostgreSQL (requiere psycopg2-binary):

yaml
authentication:
  method: database
  database_url: "postgresql://user:password@localhost:5432/potato_auth"

Potato crea la tabla users en el primer arranque y ejecuta SQLite en modo WAL para mejorar las lecturas concurrentes. database_url debe empezar por sqlite:/// o postgresql://. También puedes definir POTATO_DB_CONNECTION en el entorno; si ambos están presentes, database_url tiene prioridad.

Nota: method: database y user_config_path son mutuamente excluyentes, así que elige una sola estrategia de persistencia. Potato genera un error si se configuran los dos.

Restablecer contraseñas

CLI de administración

Restablece una contraseña desde la línea de comandos:

bash
# Prompts for username and password
potato reset-password config.yaml
 
# Prompts for the password only
potato reset-password config.yaml --username annotator1

API de administración

Restablece la contraseña mediante programación con la clave de API de administración:

bash
curl -X POST http://localhost:8000/admin/reset_password \
  -H "X-API-Key: $ADMIN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"username": "annotator1", "new_password": "new-secure-password"}'

La clave se toma, por este orden, del ajuste de nivel superior admin_api_key, de la variable de entorno POTATO_ADMIN_API_KEY o de un archivo admin_api_key.txt generado en el directorio de la tarea.

Restablecimiento de autoservicio con token

Los anotadores que olvidan su contraseña pueden restablecerla por su cuenta. Entran en /forgot-password y escriben su nombre de usuario, y Potato genera un token de un solo uso válido durante 24 horas. El enlace de restablecimiento se muestra en pantalla para que un administrador lo haga llegar; Potato no envía correos. El anotador abre /reset/<token> y define una contraseña nueva, lo que consume el token.

El flujo no necesita configuración. Cuando require_password: true está activado, aparece un enlace "Forgot Password?" en la página de inicio de sesión.

Los administradores también pueden generar un token directamente:

bash
curl -X POST http://localhost:8000/admin/create_reset_token \
  -H "X-API-Key: $ADMIN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"username": "annotator1"}'
 
# {"reset_link": "http://localhost:8000/reset/abc123...",
#  "token": "abc123...", "expires_in_hours": 24}

Pasa "ttl_hours": 48 en el cuerpo de la solicitud para usar otra caducidad.

Modo sin contraseña

Para demostraciones en clase, estudios rápidos o tareas que usan autenticación externa (MTurk, Prolific), puedes desactivar las contraseñas por completo:

yaml
require_password: false
 
authentication:
  method: in_memory

Los anotadores escriben cualquier nombre de usuario para entrar y no aparece ninguna petición de contraseña. No es recomendable con datos sensibles ni en tareas que exijan identidad verificada.

Consulta Inicio de Sesión sin Contraseña para más detalles.

Referencia completa

yaml
# Top-level: require a password at login (default: true)
require_password: true
 
# Top-level: key for the admin endpoints
admin_api_key: ${POTATO_ADMIN_API_KEY}
 
authentication:
  # in_memory (default) | database | clerk | oauth
  method: in_memory
 
  # in_memory only, mutually exclusive with method: database
  user_config_path: users.jsonl
 
  # database only; sqlite:/// or postgresql://
  # database_url: "sqlite:///auth.db"
 
user_config:
  users:
    - username: "researcher"
      password: "secure-passphrase"
    - username: "annotator1"
      password: "initial-pass"
EndpointMétodoAutenticaciónDescripción
/forgot-passwordGET, POSTningunaSolicitar un token de restablecimiento
/reset/<token>GET, POSTningunaDefinir una contraseña nueva
/admin/reset_passwordPOSTclave de APIRestablecimiento de contraseña por un administrador
/admin/create_reset_tokenPOSTclave de APIGenerar un token de restablecimiento

Lecturas adicionales

Para detalles de implementación, consulta la documentación fuente.