Callbacks et génération de formulaire
Ce tutoriel construit un graphe d’authentification minimal (nom d’utilisateur → mot de passe → vérification LDAP), puis explique le mécanisme des callbacks : comment TOSIAM décrit, de façon générique, l’information qu’il attend de l’utilisateur, et comment le client de connexion transforme automatiquement cette description en formulaire HTML.
up, accessible sur http://localhost:8080/tosiam.Étape 1 — Créer le graphe
Le graphe le plus simple qui authentifie réellement un utilisateur enchaîne trois nœuds : collecte du nom d’utilisateur, collecte du mot de passe, vérification contre le User Store.
UsernameCollectorNode ──outcome──▶ PasswordCollectorNode ──outcome──▶ DataStoreNode ──true──▶ SuccessNode
└──false──▶ FailureNode
{
"startNodeId": "username",
"steps": {
"username": { "type": "UsernameCollectorNode", "config": {}, "outcomes": { "outcome": "password" } },
"password": { "type": "PasswordCollectorNode", "config": {}, "outcomes": { "outcome": "check" } },
"check": {
"type": "DataStoreNode",
"config": { "authLevel": 0 },
"outcomes": { "true": "success", "false": "failure" }
},
"success": { "type": "SuccessNode", "config": {}, "outcomes": {} },
"failure": { "type": "FailureNode", "config": {}, "outcomes": {} }
}
}
Enregistrez ce contenu dans graphe-simple.json, à la racine du projet généré, puis créez le graphe via le goal ssoadm du plugin Maven :
mvn org.tst.tosiam:tosiam-project-generator-maven-plugin:3.36.0:ssoadm \
-Dssoadm.args="create-auth-graph --realm / --name simple --datafile $(pwd)/graphe-simple.json"
ssoadm exécute le script dans tosiam-quickstart/, pas à la racine du projet : utilisez toujours un chemin absolu pour --datafile ($(pwd)/... depuis la racine du projet généré), sans quoi le fichier ne sera pas trouvé.Étape 2 — Exposer le graphe comme point d’entrée
Un graphe seul n’est pas directement authentifiable : il faut d’abord l’instancier comme module d’authentification, puis l’exposer via une Authentication Configuration — l’équivalent TOSIAM d’une chaîne — du même nom, qui la référence.
# 1. Instancier le module AuthGraph, en le pointant vers le graphe
mvn org.tst.tosiam:tosiam-project-generator-maven-plugin:3.36.0:ssoadm \
-Dssoadm.args="create-auth-instance --realm / --name simple --authtype AuthGraph"
mvn org.tst.tosiam:tosiam-project-generator-maven-plugin:3.36.0:ssoadm \
-Dssoadm.args="update-auth-instance --realm / --name simple --attributevalues tosiam-auth-graph-id=simple"
# 2. L'exposer via une configuration d'authentification du même nom
mvn org.tst.tosiam:tosiam-project-generator-maven-plugin:3.36.0:ssoadm \
-Dssoadm.args="create-auth-cfg --realm / --name simple"
mvn org.tst.tosiam:tosiam-project-generator-maven-plugin:3.36.0:ssoadm \
-Dssoadm.args="add-auth-cfg-entr --realm / --name simple --modulename simple --criteria REQUISITE"
create-auth-graph (étape 1), create-auth-instance et create-auth-cfg (étape 2) prennent chacun un --name : on leur a donné la même valeur simple par simplicité, mais ce sont trois objets distincts (un graphe, une instance de module, une configuration). Le nom qui compte pour l’URL d’authentification est celui de la configuration, pas celui du graphe.Une dernière commande, optionnelle mais utile pour l’étape 5 : par défaut, un utilisateur non administrateur qui s’authentifie est redirigé vers la console legacy (/console/), qui le renvoie elle-même vers une page de profil minimale. Pour le rediriger plutôt vers l’application account générée par le plugin (module account du projet, voir Générer un projet avec Maven), configurez l’URL de dashboard du realm :
mvn org.tst.tosiam:tosiam-project-generator-maven-plugin:3.36.0:ssoadm \
-Dssoadm.args="add-svc-realm --realm / --servicename selfService --attributevalues selfServiceDashboardUrl=account"
Étape 3 — Le concept de callback
Le moteur de graphe (GraphEngine) ne sait rien afficher : quand un nœud a besoin d’une information, il retourne REQUEST_INPUT, et le serveur REST traduit ce besoin en un ou plusieurs callbacks — hérité directement du mécanisme JAAS (javax.security.auth.callback) sur lequel TOSIAM est construit. Un callback ne décrit jamais du HTML : il déclare seulement un type (NameCallback, PasswordCallback, ChoiceCallback…), un output en lecture seule (typiquement un prompt à afficher) et un input vide, à remplir par le client puis à reposter tel quel.
Appelons directement l’API REST pour observer cet échange, sans passer par aucune interface. Trois en-têtes sont obligatoires sur ce endpoint : Content-Type, X-Requested-With (protection CSRF) et Accept-API-Version (sélection de version de l’API) :
curl -s -X POST \
"http://localhost:8080/tosiam/json/authenticate?authIndexType=service&authIndexValue=simple" \
-H "Content-Type: application/json" \
-H "X-Requested-With: XMLHttpRequest" \
-H "Accept-API-Version: protocol=1.0,resource=2.0"
{
"authId": "eyAidHlwIjogIkpXVCIsIC...",
"template": "",
"stage": "UsernameCollectorNode",
"header": "",
"callbacks": [
{
"type": "NameCallback",
"output": [ { "name": "prompt", "value": "Username" } ],
"input": [ { "name": "IDToken1", "value": "" } ]
}
]
}
Le nœud UsernameCollectorNode s’est traduit en un unique callback NameCallback. authId identifie la conversation en cours (un JWT signé, à renvoyer intact à chaque étape) ; IDToken1 est le nom de champ que le serveur attend en retour — pas un nom métier comme username.
On répond en repostant le même JSON, authId inclus, avec input[0].value rempli, sur l’URL sans les paramètres de requête (la conversation est maintenant portée par authId) :
curl -s -X POST "http://localhost:8080/tosiam/json/authenticate" \
-H "Content-Type: application/json" \
-H "X-Requested-With: XMLHttpRequest" \
-H "Accept-API-Version: protocol=1.0,resource=2.0" \
-d '{
"authId": "eyAidHlwIjogIkpXVCIsIC...",
"callbacks": [
{
"type": "NameCallback",
"output": [ { "name": "prompt", "value": "Username" } ],
"input": [ { "name": "IDToken1", "value": "demo" } ]
}
]
}'
amadmin) est bloqué par TOSIAM pour toute authentification passant par un graphe personnalisé — une tentative échoue immédiatement (400 Authentication failed), avant même de demander le mot de passe. C’est une protection délibérée : amadmin ne doit s’authentifier que par une configuration de confiance fixe, jamais par un module que n’importe quel utilisateur du realm peut créer. Utilisez un compte utilisateur ordinaire du User Store — par exemple demo/changeit, fourni par défaut dans les données du QuickStart.Le graphe avance au nœud suivant et répond avec un nouveau callback, cette fois PasswordCallback :
{
"authId": "eyAidHlwIjogIkpXVCIsIC...",
"stage": "PasswordCollectorNode",
"callbacks": [
{
"type": "PasswordCallback",
"output": [ { "name": "prompt", "value": "Password" } ],
"input": [ { "name": "IDToken1", "value": "" } ]
}
]
}
En repostant ce callback rempli (demo / changeit), DataStoreNode vérifie les identifiants contre le User Store puis transitionne silencieusement (c’est un nœud de décision : il ne produit jamais de callback) vers SuccessNode. La réponse finale ne contient plus de callback :
{
"tokenId": "fl82k0p9enspW4CCrGZkiJl9EMs.*AAJTSQACMDEAAlNLABxweFBDMEtFRmVOcFRtR042N2ZYVGs0eExSajg9AAJTMQAA*",
"successUrl": "/console/"
}
accompagnée d’un cookie de session (iPlanetDirectoryPro, valeur = tokenId) — c’est la session TOSIAM.
NameCallback (texte visible), PasswordCallback (masqué, jamais renvoyé en clair dans output), ChoiceCallback (liste de choix), ConfirmationCallback (boutons), TextOutputCallback (message informatif, sans saisie)… Voir le catalogue des nœuds — Collecteurs.Étape 4 — La génération automatique de formulaire
C’est exactement ce même contrat JSON que consomme tosiam-authentication-ui, le client de connexion HTML/TS livré avec TOSIAM (module auth du projet généré, voir Générer un projet avec Maven). Il ne connaît jamais à l’avance la liste des nœuds d’un graphe donné : il se contente d’inspecter le champ type de chaque callback reçu, et de le confier à une fabrique qui choisit le bon élément de formulaire :
Stage { callbacks: [...] }
│
▼ pour chaque callback, selon callback.type
FormElementFactory.getFormElement(type, callbackIndex)
│
├─ "NameCallback" → DefaultCallback (<input type="text" autocomplete="username">)
├─ "PasswordCallback" → PasswordCallback (<input type="password"> + bouton afficher/masquer)
├─ "ChoiceCallback" → ChoiceCallback (liste de choix)
├─ ...
└─ type inconnu → DefaultCallback (repli générique)
Chaque élément produit son propre fragment HTML (getHtml()), assemblé dans un <form> unique. À la soumission, le client relit la valeur saisie pour chaque champ, l’écrit dans callback.input[0].value, puis reposte le tableau callbacks complet sur /authenticate — exactement l’échange REST reproduit à l’étape précédente avec curl. Rien dans ce mécanisme générique ne fait référence à UsernameCollectorNode ou PasswordCollectorNode : ce sont uniquement les types de callback (NameCallback, PasswordCallback) qui pilotent le rendu.
Cela a une conséquence directe pour vos graphes personnalisés : tant qu’un nœud custom retourne un callback d’un type standard, il s’affiche automatiquement, sans aucun développement front-end. TOSIAM enregistre en plus, pour une poignée de nœuds qui ont besoin de plus qu’un simple champ (WebAuthn, QR code TOTP, reCAPTCHA…), des rendus spécifiques indexés sur le nom du nœud plutôt que sur le type de callback — mais même ceux-ci s’appuient sur le même mécanisme générique pour leurs champs de formulaire ordinaires. En l’absence de rendu spécifique, c’est ce mécanisme générique qui s’applique — c’est le cas de notre graphe simple.
Étape 5 — Se connecter dans le navigateur
Ouvrez http://localhost:8080/tosiam/auth/#login?service=simple (le realm racine / est celui par défaut, inutile de le préciser). Le formulaire nom d’utilisateur s’affiche — généré automatiquement à partir du callback NameCallback vu plus haut, sans aucune ligne de CSS ou de JS écrite pour ce graphe :

Saisissez demo, validez : le second callback (PasswordCallback) produit un champ masqué avec bouton afficher/masquer :

Saisissez changeit : DataStoreNode valide les identifiants, la session est ouverte, et — grâce au selfServiceDashboardUrl configuré à l’étape précédente — le navigateur est redirigé vers l’application account du projet généré :
