This release is a pre-release and may not be stable for production use.
forge-mvc-mfa
Brique MFA (TOTP + codes de récupération) pour le framework Forge.
Un opt-in officiel
Cet opt-in suit la version du cœur de Forge et n'a pas de cycle de maturité
propre : sa version est celle du pyproject.toml racine (OPTINS-MATURITY-FOLLOWS-CORE-001).
Depuis SEC-MFA-SECRET-ENCRYPTION-001, le secret TOTP est chiffré au repos
via Fernet (cryptography). La clé est lue depuis FORGE_MFA_SECRET_KEY,
obligatoire au démarrage, et MFA-KEY-ROTATION-001 en livre la rotation.
Le module est publié sur PyPI (MFA-PYPI-READY-001). Il reste hors de
forge-mvc[all] : l'installer directement, car l'activation de la MFA est un
choix de sécurité explicite de l'application.
Installation :
pip install --pre forge-mvc-mfa
Pour développer le paquet en mode éditable depuis les sources du dépôt Forge :
git clone https://github.com/caucrogeGit/Forge.git
cd Forge
pip install -e .
pip install -r requirements-dev.txt
Configuration requise — FORGE_MFA_SECRET_KEY
forge-mvc-mfa chiffre les secrets TOTP au repos via Fernet et exige une
clé valide dans l'environnement. Forge refuse explicitement les valeurs
absentes, vides, ou placeholder (change-me, default, dev, secret,
test, …) — voir MFA-SECRET-KEY-BOOT-VALIDATION-001.
# Générer une clé Fernet (à stocker dans .env ou un gestionnaire de secrets).
python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
Ajouter dans .env :
FORGE_MFA_SECRET_KEY=<clé générée ci-dessus>
Ne JAMAIS commiter cette clé dans le dépôt. Utiliser .env,
un gestionnaire de secrets (Vault, AWS Secrets Manager, etc.) ou les
variables d'environnement du runtime de production.
Rotation de la clé — FORGE_MFA_SECRET_KEY_PREVIOUS
Changer la clé sans précaution rend tous les secrets TOTP illisibles au même instant, et chaque porteur d'un facteur perd son second facteur.
FORGE_MFA_SECRET_KEY_PREVIOUS déclare les clés retirées, séparées par des
virgules. Elles servent uniquement au déchiffrement, le chiffrement utilisant
toujours la clé courante.
FORGE_MFA_SECRET_KEY=<nouvelle clé>
FORGE_MFA_SECRET_KEY_PREVIOUS=<ancienne clé>
Les secrets existants se rechiffrent ensuite au rythme voulu, puis la variable se retire :
from forge_mvc_mfa import rotate_totp_secret, uses_current_key
for facteur in mes_facteurs_totp():
if not uses_current_key(facteur.totp_secret):
enregistrer(facteur.id, rotate_totp_secret(facteur.totp_secret))
Forge ne balaie pas la base lui-même : la table des facteurs appartient à
l'application, dont Forge ne connaît ni le nom ni les colonnes. Une clé retirée
reste un secret tant qu'elle est déclarée. Voir MFA-KEY-ROTATION-001 et la
procédure complète dans la référence de l'opt-in.
Validation au démarrage
Pour échouer tôt en production plutôt qu'à la première opération MFA, appeler la validation explicite au boot de l'application :
from forge_mvc_mfa import validate_mfa_secret_key_config
# Au démarrage de l'application — par exemple dans app.py ou wsgi.py.
# Lève MfaSecretKeyMissing / MfaSecretKeyPlaceholder / MfaSecretInvalidKey
# avec un message d'erreur exploitable. Aucune valeur de clé n'est loguée.
validate_mfa_secret_key_config()
MFA reste opt-in : Forge ne force pas cette validation au niveau du
core. C'est l'application qui choisit de l'appeler quand elle active MFA.
Une application qui installe forge-mvc-mfa mais ne l'utilise pas n'est
jamais bloquée.
Exceptions levées
| Exception | Cause |
|---|---|
MfaSecretKeyMissing |
FORGE_MFA_SECRET_KEY absent ou vide |
MfaSecretKeyPlaceholder |
valeur reconnue comme placeholder (change-me, etc.) |
MfaSecretInvalidKey |
format Fernet invalide (longueur ou base64) |
Aucune de ces exceptions ne contient la valeur de la clé tentée — pour éviter de fuir un secret dans un log applicatif. Le message indique toujours la commande de génération d'une clé valide.
Installation (mode source)
# Depuis le dépôt Forge (mode développement)
pip install -r requirements-dev.txt # installe forge-mvc-mfa depuis packages/
forge-mvc-mfa dépend de pyotp>=2.9.
Utilisation
from forge_mvc_mfa import (
AuthMfaFactor,
create_totp_factor,
confirm_totp_factor,
verify_mfa_challenge,
is_mfa_enabled,
)
L'API complète est exposée directement depuis forge_mvc_mfa.
Les fonctions privées (_persist_session_changes, _session_user_matches)
doivent être importées depuis forge_mvc_mfa.mfa.
SQL
Les tables MFA (auth_mfa_factors, auth_mfa_recovery_codes) sont générées
dans votre projet par la commande du core forge auth:init, puis appliquées
avec forge db:apply. Les fichiers sql/ du dépôt source en sont la référence
(ils ne sont pas livrés dans le wheel : la DDL est embarquée par auth:init).
Compatibilité
Extrait du cœur par l'ADR-004 (MFA-EXTRACT-001). Les anciens chemins
core.auth.mfa, core.auth.recovery et core.auth.totp_replay ont été
retirés depuis, sous une numérotation antérieure au renumérotage vers 1.0.
Limites connues
- Le registre anti-rejeu vit en mémoire du processus par défaut. Forge
livre
DbTotpReplayStore, adossé au backend BDD, donc commun à tous les workers ; l'application le pose au démarrage en une ligne visible. Les sticky sessions ne sont pas la réponse recommandée : elles déplacent le problème sans le résoudre. - Le rate-limit du challenge vit lui aussi en mémoire du processus, et les cinq
essais deviennent donc
5 × Nworkers. La parade se pose au proxy, et la configuration Nginx engendrée parforge deploy:initla porte sur/logindepuisDEPLOY-NGINX-RATE-LIMIT-001. Le challenge MFA vit sur une autre route, que Forge ne connaît pas : ajoutez unlocationde même forme. - La rotation de la clé Fernet est livrée (
MFA-KEY-ROTATION-001) :FORGE_MFA_SECRET_KEY_PREVIOUS,rotate_totp_secret,uses_current_key. La procédure de sauvegarde de la clé relève de l'exploitant.
Release files for forge-mvc-mfa 1.0.0rc9
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| forge_mvc_mfa-1.0.0rc9.tar.gz | 40.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| forge_mvc_mfa-1.0.0rc9-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 75.1 kB
Release files / forge_mvc_mfa-1.0.0rc9.tar.gz
| Download URL | forge_mvc_mfa-1.0.0rc9.tar.gz |
|---|---|
| Size | 40.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f9df1bb2493baf675a87d5b6cbc0e758962f2dc01a9488b2c7dd35bcb496e477
|
|
BLAKE2b-256 checksum How to use checksums |
de769a6eac9a54e9b28a68be3156d4bb7c94d91941418a1b0f22fb924a2055fa
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.13
|
Release files / forge_mvc_mfa-1.0.0rc9-py3-none-any.whl
| Download URL | forge_mvc_mfa-1.0.0rc9-py3-none-any.whl |
|---|---|
| Size | 34.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
d323116032199881226dc474d3c5b7b45d71811ef997932e9ee3d31f3608efce
|
|
BLAKE2b-256 checksum How to use checksums |
79633ec0d6cb4fd6139ceb2267fccd9f70c2d4a0521a58745b235a140a31d536
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.13
|