TutorielGuides

Double authentification par e-mail (SMTP)

Sur cette page

Ce tutoriel ajoute un second facteur à la connexion : après son mot de passe, l’utilisateur reçoit un code à six chiffres par e-mail et le saisit. Le code est tiré au hasard à chaque connexion et expire au bout de cinq minutes.

Le nœud EmailOtpSendNode n’a pas de réglage SMTP : il envoie le message par le service de messagerie du royaume (Email Service), qui désigne le serveur SMTP, le port, le chiffrement et l’adresse d’expédition. Pour suivre le tutoriel sans serveur de messagerie, un faux serveur SMTP, un petit programme Node.js, reçoit les e-mails et les affiche dans le navigateur.

Étape 1 : l’adresse e-mail#

TOSIAM lit l’adresse dans l’attribut mail du profil. Pour l’utilisateur dduck :

bash
curl -X PUT "http://localhost:8080/tosiam/json/ref/users/dduck" \
     -H "Content-Type: application/json" \
     -H "X-Requested-With: XMLHttpRequest" \
     -H "Accept-API-Version: resource=3.0, protocol=1.0" \
     -H "iPlanetDirectoryPro: <jeton administrateur>" \
     -d '{"mail": ["donald.duck@example.com"]}'

Étape 2 : le faux serveur SMTP#

Téléchargez faux-smtp.mjs et lancez-le :

bash
node faux-smtp.mjs

Il écoute en SMTP sur le port 2525, sans chiffrement ni authentification, et accepte tous les messages sans les remettre. Sa boîte de réception est sur http://localhost:8025. Les variables SMTP_PORT et HTTP_PORT changent ces ports.

Étape 3 : le service de messagerie du royaume#

Un royaume neuf n’a pas de service de messagerie : sans lui, aucun nœud ne peut envoyer d’e-mail. Dans le royaume ref, ouvrez Services › Ajouter un service, choisissez Email Service (Service de messagerie), puis renseignez :

Faites défiler le tableau
RéglageValeurChamp REST
Nom d’hôte du serveur de messagerielocalhosthostname
Port du serveur de messagerie2525port
Connexion sécurisée au serveur de messagerieNon SSLsslState
Adresse d’expéditionTOSIAM <no-reply@example.com>from
Console, page Email Service du royaume ref : nom d'hôte localhost, port 2525, connexion sécurisée Non SSL, adresse d'expédition TOSIAM <no-reply@example.com>, nom d'utilisateur et mot de passe vides Console, page Email Service du royaume ref : nom d'hôte localhost, port 2525, connexion sécurisée Non SSL, adresse d'expédition TOSIAM <no-reply@example.com>, nom d'utilisateur et mot de passe vides
Le service de messagerie du royaume ref : serveur (1), port (2), chiffrement (3) et adresse d’expédition (4).

Laissez vides le nom d’utilisateur et le mot de passe : le faux serveur ne demande pas d’authentification.

Le même service se crée par l’API REST :

bash
curl -X POST "http://localhost:8080/tosiam/json/ref/realm-config/services/email?_action=create" \
     -H "Content-Type: application/json" \
     -H "X-Requested-With: XMLHttpRequest" \
     -H "Accept-API-Version: resource=1.0" \
     -H "iPlanetDirectoryPro: <jeton administrateur>" \
     -d '{"hostname": "localhost", "port": 2525, "sslState": "Non SSL", "from": "TOSIAM <no-reply@example.com>"}'

Une fois le service créé, la même adresse modifie un réglage avec PUT (sans ?_action=create), par exemple {"port": 587}.

Le service de messagerie est réglé une fois pour tout le royaume : EmailOtpSendNode, mais aussi MagicLinkSendNode (lien magique), s’en servent.

Étape 4 : le graphe#

Graphe connexion-email dans l'éditeur : identifiant et mot de passe, vérification du mot de passe, envoi du code par e-mail, code reçu par e-mail, puis succès ou échec ; false revient sur le code reçu et expired renvoie vers l'envoi Graphe connexion-email dans l'éditeur : identifiant et mot de passe, vérification du mot de passe, envoi du code par e-mail, code reçu par e-mail, puis succès ou échec ; false revient sur le code reçu et expired renvoie vers l'envoi
Le graphe connexion-email : le code est envoyé après le mot de passe, puis vérifié. Un code faux redemande la saisie (false), un code expiré en fait envoyer un nouveau (expired).
Faites défiler le tableau
ÉtapeNœudRôle
Identifiant et mot de passePageNode (UsernameCollectorNode + PasswordCollectorNode)Un seul écran pour les deux champs
Vérification du mot de passeDataStoreNodeContrôle dans l’annuaire du royaume
Envoi du code par e-mailEmailOtpSendNodeTire un code, le garde dans l’état partagé du parcours et l’envoie à l’adresse de l’utilisateur ; error si l’utilisateur n’a pas d’adresse ou si l’envoi échoue
Code reçu par e-mailEmailOtpVerifyNodeCompare le code saisi : true s’il est juste, false s’il est faux, exceeded s’il est faux et que c’était le dernier essai (maxAttempts), expired s’il a expiré

Le nœud d’envoi, dans le graphe :

json· connexion-email.json (extrait)
"envoi": {
  "type": "EmailOtpSendNode",
  "config": {
    "otpLength": 6,
    "ttlSeconds": 300,
    "emailAttribute": "mail",
    "emailSubject": "Votre code de connexion TOSIAM",
    "emailBodyTemplate": "Bonjour,\n\nVotre code de connexion est : {otp}\n\nIl expire dans {ttl} secondes. Si vous n'êtes pas à l'origine de cette demande, ignorez ce message."
  },
  "outcomes": { "sent": "code", "error": "echec" }
},
"code": {
  "type": "EmailOtpVerifyNode",
  "config": { "maxAttempts": 3 },
  "outcomes": { "true": "succes", "false": "code", "exceeded": "echec", "expired": "envoi" }
}

Dans emailBodyTemplate, {otp} est remplacé par le code et {ttl} par sa durée de validité en secondes. Le message part en texte brut, encodé en UTF-8 : les accents passent sans précaution. L’objet (emailSubject) ne doit pas contenir de retour à la ligne, sinon l’envoi est refusé.

Le câblage de EmailOtpVerifyNode accorde trois essais :

  • false → EmailOtpVerifyNode : après un code faux, la saisie revient ;
  • exceeded → Échec : le troisième code faux termine la connexion ;
  • expired → EmailOtpSendNode : un nouvel e-mail part et le nouveau code est demandé.

Le graphe complet est disponible en JSON : connexion-email.json. Chaque nœud est décrit dans Nœuds : OTP SMS / Email.

Étape 5 : importer et exposer le graphe#

Dans le royaume ref :

  1. Graphes d’authentification › Importer : choisissez connexion-email.json.
  2. Ouvrez le graphe et cliquez sur Exposer ce graphe comme parcours de connexion.

Le parcours est accessible à l’adresse :

texte
http://localhost:8080/tosiam/auth/?realm=ref&module=connexion-email

Étape 6 : se connecter#

Ouvrez l’adresse du parcours et connectez-vous avec dduck.

Page de connexion TOSIAM : nom d'utilisateur dduck et mot de passe sur le même écran, bouton Se connecter Page de connexion TOSIAM : nom d'utilisateur dduck et mot de passe sur le même écran, bouton Se connecter
Identifiant et mot de passe, sur un seul écran.

Le mot de passe est juste : TOSIAM envoie l’e-mail et demande le code.

Écran Saisissez le code envoyé à votre adresse e-mail, avec six cases et le bouton Vérifier Écran Saisissez le code envoyé à votre adresse e-mail, avec six cases et le bouton Vérifier
La saisie du code : le formulaire part dès le sixième chiffre.

Ouvrez http://localhost:8025 dans un autre onglet : le faux serveur affiche l’e-mail reçu, avec l’expéditeur, l’objet, le texte et le code en gros.

Page Faux SMTP : un e-mail de TOSIAM <no-reply@example.com> à donald.duck@example.com, objet Votre code de connexion TOSIAM, avec le texte et le code en grand Page Faux SMTP : un e-mail de TOSIAM <no-reply@example.com> à donald.duck@example.com, objet Votre code de connexion TOSIAM, avec le texte et le code en grand
L’e-mail tel que TOSIAM l’a envoyé, reçu par le faux serveur SMTP.

Le terminal du faux serveur l’annonce aussi :

texte
2026-10-23T07:36:23.507Z  e-mail pour donald.duck@example.com : Votre code de connexion TOSIAM

Saisissez le code : la connexion aboutit. Un code faux redemande la saisie ; au troisième code faux, la connexion se termine sur la page Échec de la connexion à TOSIAM.

Pour vérifier sans navigateur, le même parcours se joue par l’API REST : voir Authentification REST, avec authIndexType=module&authIndexValue=connexion-email. Le code se saisit dans le PasswordCallback de l’étape EmailOtpVerifyNode.

En production : un vrai serveur SMTP#

Seul le service de messagerie du royaume change ; le graphe reste le même.

Faites défiler le tableau
RéglageChamp RESTValeurs
Nom d’hôtehostnameServeur SMTP de l’organisation ou du fournisseur d’envoi (smtp.example.com)
Portport465 pour SSL, 587 pour STARTTLS, 25 pour Non SSL
Connexion sécuriséesslStateSSL (TLS dès la connexion, la valeur par défaut), STARTTLS (connexion en clair puis passage en TLS ; l’envoi échoue si le serveur ne le propose pas) ou Non SSL
Nom d’utilisateur, mot de passeusername, passwordCompte d’envoi ; l’authentification SMTP n’est faite que si les deux sont renseignés
Adresse d’expéditionfromAdresse que le serveur SMTP accepte comme expéditeur, avec ou sans nom affiché

TOSIAM garde le mot de passe chiffré dans sa configuration et ne le renvoie jamais en lecture ("password": null).

Réglages utiles#

Faites défiler le tableau
RéglageNœudEffet
ttlSeconds (300)EmailOtpSendNodeDurée de validité du code, en secondes
emailSubjectEmailOtpSendNodeObjet de l’e-mail, sur une seule ligne
emailBodyTemplateEmailOtpSendNodeTexte de l’e-mail, avec {otp} et {ttl}
emailAttribute (mail)EmailOtpSendNodeAttribut du profil qui contient l’adresse
emailSharedStateKey (email)EmailOtpSendNodeClé de l’état partagé lue avant le profil
otpLength (6)EmailOtpSendNodeLongueur du code
maxAttempts (5)EmailOtpVerifyNodeNombre de codes faux admis ; le dernier passe par exceeded

L’adresse est cherchée d’abord dans l’état partagé, sous la clé emailSharedStateKey, puis dans le profil. Un nœud placé avant l’envoi qui y range une adresse saisie permet de vérifier une adresse que le profil n’a pas encore.

En cas de problème#

Les erreurs d’envoi mènent à la sortie error du nœud, donc à Échec de la connexion dans ce graphe ; la cause est dans catalina.out, sous la ligne Failed to send OTP email to '…' for user '…'.

Faites défiler le tableau
Symptôme dans catalina.outCause probable
NullPointerException: Cannot invoke "String.length()" because "s" is nullLe royaume n’a pas de service de messagerie (étape 3)
the 'Email From Address' configuration is emptyService présent, mais sans adresse d’expédition (from)
MailConnectException: Couldn't connect to host, port: …Aucun serveur SMTP à cette adresse et ce port : faux serveur arrêté, mauvais port, ou localhost vu depuis un conteneur (encadré de l’étape 3)
MessagingException: Could not connect to SMTP host aussitôt, alors que le serveur écouteSSL choisi pour un serveur qui attend du texte en clair ou STARTTLS : réglez Connexion sécurisée selon le port
AuthenticationFailedExceptionNom d’utilisateur ou mot de passe SMTP refusé par le serveur
Cannot resolve email for userL’utilisateur n’a pas d’attribut mail (étape 1)
Rien dans les journaux, mais l’e-mail n’arrive pasLe serveur SMTP a accepté le message : cherchez du côté de la remise (spam, SPF/DKIM, adresse du destinataire)

Pour aller plus loin#

Mis à jour le