Gestion des mots de passe
Configurez le hachage PBKDF2-SHA256 des mots de passe, les réinitialisations par CLI ou API admin, les liens de réinitialisation en libre-service par jeton, et le stockage des identifiants en SQLite ou PostgreSQL dans Potato.
Nouveau dans la v2.4.0
Le système d'authentification de Potato utilise PBKDF2-SHA256 avec 100 000 itérations et un sel propre à chaque utilisateur, l'approche que le NIST recommande pour le stockage sécurisé des mots de passe. Cette page explique comment les mots de passe sont stockés, comment les réinitialiser et comment conserver les identifiants d'un redémarrage du serveur à l'autre.
Elle concerne les méthodes in_memory et database. Avec OAuth, c'est le fournisseur d'identité qui gère le mot de passe, donc rien de tout cela ne s'applique, sauf aux comptes locaux en mode mixte.
Mise en œuvre de la sécurité
Les mots de passe sont stockés au format salt$hash :
- Un sel hexadécimal de 32 caractères, unique par utilisateur
- Un condensat hexadécimal de 64 caractères, dérivé par PBKDF2-HMAC-SHA256 à partir du mot de passe, avec ce sel et 100 000 itérations
- Une comparaison à temps constant via
hmac.compare_digest, qui empêche les attaques temporelles
Une seule passe de SHA-256 sur un mot de passe salé est assez rapide pour permettre une attaque par force brute à grande échelle. Ce sont les 100 000 itérations qui rendent chaque essai coûteux.
Les mots de passe en clair présents dans les fichiers user_config.json sont re-hachés automatiquement avec des sels uniques au chargement par Potato. Aucune migration manuelle n'est nécessaire.
Configuration par défaut
Par défaut, Potato utilise une authentification en mémoire. require_password est une clé de premier niveau, et non une partie du bloc authentication :
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"Identifiants persistants
Les comptes créés via le formulaire d'inscription sont écrits dans un fichier JSONL et relus au démarrage suivant. Avec in_memory, ce fichier est user_config.json, à côté du répertoire de sortie, sauf si vous en indiquez un autre.
Persistance par fichier
authentication:
method: in_memory
user_config_path: /shared/path/to/user_config.jsonlIndiquez un chemin quand plusieurs instances du serveur partagent une même liste d'utilisateurs, ou quand vous voulez placer cette liste ailleurs qu'à côté des annotations. Les nouvelles inscriptions et les changements de mot de passe sont écrits au fur et à mesure.
Conservez la liste d'utilisateurs avec les résultats d'annotation. Le répertoire d'un annotateur porte son nom d'utilisateur. Si la liste d'utilisateurs a disparu alors que le répertoire de sortie existe encore, la prochaine personne qui saisirait ce nom d'utilisateur hériterait du travail de quelqu'un d'autre. Potato refuse donc l'inscription, ce qui signifie que l'annotateur ne peut pas revenir tant que vous n'avez pas restauré le fichier.
Avant la v2.8.3, in_memory n'écrivait rien si user_config_path n'était pas défini explicitement, et les comptes ne survivaient donc pas à un redémarrage. Si vous avez mené une étude sur une version antérieure, ces comptes sont perdus ; les annotations, elles, ne le sont pas.
Base de données
SQLite (aucune dépendance supplémentaire) :
authentication:
method: database
database_url: "sqlite:///auth/users.db"PostgreSQL (nécessite psycopg2-binary) :
authentication:
method: database
database_url: "postgresql://user:password@localhost:5432/potato_auth"Potato crée la table users au premier démarrage et fait tourner SQLite en mode WAL pour de meilleures lectures concurrentes. database_url doit commencer par sqlite:/// ou postgresql://. Vous pouvez aussi définir POTATO_DB_CONNECTION dans l'environnement ; database_url l'emporte quand les deux sont présents.
Remarque : method: database et user_config_path s'excluent mutuellement. Choisissez une seule stratégie de persistance. Potato lève une erreur si les deux sont configurés.
Réinitialiser les mots de passe
CLI d'administration
Réinitialisez un mot de passe en ligne de commande :
# Prompts for username and password
potato reset-password config.yaml
# Prompts for the password only
potato reset-password config.yaml --username annotator1API d'administration
Réinitialisez par programme avec la clé d'API d'administration :
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 clé provient, dans cet ordre, du réglage de premier niveau admin_api_key, de la variable d'environnement POTATO_ADMIN_API_KEY ou d'un fichier admin_api_key.txt généré dans le répertoire de la tâche.
Réinitialisation en libre-service par jeton
Les annotateurs qui oublient leur mot de passe peuvent le réinitialiser eux-mêmes. Ils se rendent sur /forgot-password et saisissent leur nom d'utilisateur, et Potato génère un jeton à usage unique valable 24 heures. Le lien de réinitialisation s'affiche à l'écran pour qu'un administrateur le transmette ; Potato n'envoie aucun e-mail. L'annotateur ouvre /reset/<token> et définit un nouveau mot de passe, ce qui consomme le jeton.
Ce parcours ne demande aucune configuration. Quand require_password: true est défini, un lien "Forgot Password?" apparaît sur la page de connexion.
Les administrateurs peuvent aussi créer un jeton directement :
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}Passez "ttl_hours": 48 dans le corps de la requête pour une autre durée de validité.
Mode sans mot de passe
Pour des démonstrations en classe, des études rapides ou des tâches qui reposent sur une authentification externe (MTurk, Prolific), vous pouvez désactiver complètement les mots de passe :
require_password: false
authentication:
method: in_memoryLes annotateurs se connectent avec n'importe quel nom d'utilisateur, sans invite de mot de passe. À éviter pour des données sensibles ou des tâches qui exigent une identité vérifiée.
Voir Connexion sans mot de passe pour les détails.
Référence complète
# 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"| Endpoint | Méthode | Auth | Description |
|---|---|---|---|
/forgot-password | GET, POST | aucune | Demander un jeton de réinitialisation |
/reset/<token> | GET, POST | aucune | Définir un nouveau mot de passe |
/admin/reset_password | POST | clé d'API | Réinitialisation du mot de passe par l'administrateur |
/admin/create_reset_token | POST | clé d'API | Générer un jeton de réinitialisation |
Pour aller plus loin
- SSO et OAuth : connexion via Google, GitHub ou le SSO de votre établissement
- Connexion sans mot de passe : accès par simple nom d'utilisateur pour les tâches ouvertes
- Configuration de production : HTTPS et configuration du reverse proxy
- Tableau de bord d'administration : gestion des comptes d'annotateurs
Pour les détails d'implémentation, consultez la documentation source.