Application web avec SAML 2.0
Sur cette page
Beaucoup d’applications d’entreprise, et la plupart des logiciels en ligne (SaaS), savent déléguer la connexion à un fournisseur d’identité SAML 2.0. TOSIAM joue ce rôle : l’application ne gère plus aucun mot de passe, elle envoie l’utilisateur chez TOSIAM et reçoit en retour une assertion signée qui dit qui il est. À la déconnexion, elle demande à TOSIAM de fermer aussi sa session : c’est la déconnexion unique (Single Logout).
Le code est dans le dépôt tosiam-samples, dossier tosiam-saml : une petite application web Node.js, sur le port 8089, qui utilise la bibliothèque @node-saml/node-saml. Côté TOSIAM, rien ne dépend de Node.js : une application Java, .NET ou PHP, ou un logiciel en ligne, se déclare de la même façon, avec ses métadonnées. Pour les notions de SAML, voir Qu’est-ce que SAML 2.0 ?.
- Navigateur vers Application (SP) « Se connecter avec TOSIAM »
-
Application (SP) vers Navigateur
Redirection vers TOSIAM avec une
AuthnRequest -
Navigateur vers TOSIAM (IdP
GET /SSORedirect/metaAlias/ref/exemple-saml-idp - TOSIAM (IdP vers Navigateur Page de connexion XUI, puis formulaire auto-envoyé
-
Navigateur vers Application (SP)
POST /saml/acs:SAMLResponse(assertion signée) - Application (SP) vers Navigateur Session de l’application, page « Profil »
Étape 1 : le vocabulaire de SAML#
| Terme | Dans l’exemple |
|---|---|
| Fournisseur d’identité (IdP) : connecte l’utilisateur et émet les assertions | TOSIAM, entité tosiam-exemple-saml-idp, royaume ref |
| Fournisseur de services (SP) : l’application qui fait confiance à l’IdP | L’application Node.js, entité tosiam-exemple-saml-application |
| Métadonnées : le document XML qui décrit une entité (adresses, certificats, formats) | Celles de TOSIAM sont publiques ; celles de l’application sont dans tosiam/application-sp.xml |
| Cercle de confiance : les fournisseurs qui acceptent de travailler ensemble | exemple-saml |
| Assertion : la déclaration signée de l’IdP (qui, quand, pour quelle application, avec quels attributs) | Signée par la clé test de la QuickStart |
| NameID : l’identifiant de l’utilisateur pour cette application | Format transient : une valeur opaque, nouvelle à chaque connexion |
Dans TOSIAM, un fournisseur est hébergé quand c’est TOSIAM lui-même (ici l’IdP), distant quand c’est un partenaire déclaré par ses métadonnées (ici l’application).
Étape 2 : créer le fournisseur d’identité et le cercle de confiance#
L’IdP hébergé se crée à partir d’un modèle, qui produit ses métadonnées avec le certificat d’une clé du keystore de TOSIAM. Les scripts de l’exemple font, avec ssoadm :
ssoadm create-cot --cot exemple-saml --realm ref
ssoadm create-metadata-templ --entityid tosiam-exemple-saml-idp \
--identityprovider /ref/exemple-saml-idp --idpscertalias test \
--meta-data-file idp.xml --extended-data-file idp-ext.xml
ssoadm import-entity --realm ref --cot exemple-saml \
--meta-data-file idp.xml --extended-data-file idp-ext.xml/ref/exemple-saml-idp est l’alias de l’IdP (metaAlias) : il apparaît dans ses adresses, par exemple /SSORedirect/metaAlias/ref/exemple-saml-idp. TOSIAM publie ensuite ses métadonnées, que l’application lit à la première connexion (pas à son démarrage) :
curl 'http://localhost:8080/tosiam/saml2/jsp/exportmetadata.jsp?entityid=tosiam-exemple-saml-idp&realm=/ref'Dans la console, le menu Fédérations du royaume ref montre les deux fournisseurs, et l’onglet « Cercle de confiance » le cercle exemple-saml. La page de l’IdP a un bouton « Exporter les métadonnées ».
ref (1), le fournisseur d’identité hébergé, c’est-à-dire TOSIAM (2), et l’application, fournisseur de services distant (3), tous deux dans un cercle de confiance.
Étape 3 : déclarer l’application#
L’application se déclare par ses métadonnées. Celles de l’exemple (tosiam/application-sp.xml) correspondent à celles que l’application sert sur http://localhost:8089/metadata, générées par node-saml (adresse de déconnexion passée en HTTP-Redirect, voir l’étape 6) :
<EntityDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata" entityID="tosiam-exemple-saml-application">
<SPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"
AuthnRequestsSigned="false" WantAssertionsSigned="true">
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
Location="http://localhost:8089/saml/slo"/>
<NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</NameIDFormat>
<AssertionConsumerService index="1" isDefault="true"
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
Location="http://localhost:8089/saml/acs"/>
</SPSSODescriptor>
</EntityDescriptor>AssertionConsumerService: l’adresse où TOSIAM envoie la réponse, en HTTP-POST.WantAssertionsSigned="true": TOSIAM signe chaque assertion pour cette application.SingleLogoutService: l’adresse où TOSIAM renvoie la réponse de déconnexion.
Ce que TOSIAM envoie, et comment, se règle dans sa configuration étendue du fournisseur (tosiam/application-sp-ext.xml) :
<EntityConfig xmlns="urn:sun:fm:SAML:2.0:entityconfig" entityID="tosiam-exemple-saml-application" hosted="0">
<SPSSOConfig>
<Attribute name="cotlist"><Value>exemple-saml</Value></Attribute>
<Attribute name="attributeMap">
<Value>uid=uid</Value>
<Value>cn=cn</Value>
<Value>mail=mail</Value>
</Attribute>
<Attribute name="wantLogoutResponseSigned"><Value>true</Value></Attribute>
</SPSSOConfig>
</EntityConfig>attributeMap: les attributs du profil ajoutés à l’assertion, sous la formenom dans l'assertion=attribut du profil. Sans correspondance, l’assertion ne contient que le NameID.wantLogoutResponseSigned: TOSIAM signe ses réponses de déconnexion pour cette application.
ssoadm import-entity --realm ref --cot exemple-saml \
--meta-data-file application-sp.xml --extended-data-file application-sp-ext.xmlLes mêmes réglages se retrouvent sur la page du fournisseur de services, dans la console :
Étape 4 : l’application#
L’application lit les métadonnées de TOSIAM (certificat de signature, adresses de connexion et de déconnexion) et règle node-saml ainsi (application/saml.js) :
new SAML({
issuer: 'tosiam-exemple-saml-application', // l'entité de l'application
callbackUrl: 'http://localhost:8089/saml/acs',
logoutCallbackUrl: 'http://localhost:8089/saml/slo',
identifierFormat: 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient',
entryPoint: idp.ssoUrl, // /SSORedirect/metaAlias/ref/exemple-saml-idp
logoutUrl: idp.sloUrl, // /IDPSloRedirect/metaAlias/ref/exemple-saml-idp
idpCert: idp.certs, // certificat publié par TOSIAM
idpIssuer: 'tosiam-exemple-saml-idp', // émetteur attendu des messages de déconnexion
audience: 'tosiam-exemple-saml-application',
wantAssertionsSigned: true,
wantAuthnResponseSigned: false, // TOSIAM signe l'assertion, pas la réponse
validateInResponseTo: 'always',
acceptedClockSkewMs: 5_000, // écart d'horloge toléré
});Avant d’ouvrir une session, node-saml vérifie que :
- l’assertion est signée par le certificat publié par TOSIAM, ce qui prouve qu’elle vient de lui ;
- elle est destinée à l’application (
Audience) ; - elle répond à une demande envoyée par l’application (
InResponseTo), une seule fois ; - elle est encore valide (
NotBefore,NotOnOrAfter, à 5 secondes près).
Une réponse rejouée, modifiée, ou envoyée par TOSIAM sans demande de l’application (connexion lancée côté IdP, par /idpssoinit) est refusée. La session de l’application tient ensuite dans un cookie aléatoire HttpOnly.
Étape 5 : se connecter#
Démarrez l’exemple, puis ouvrez http://localhost:8089 :
./up.sh # Windows : up.bat
« Se connecter avec TOSIAM » envoie le navigateur chez TOSIAM. Sans session, TOSIAM affiche sa page de connexion du royaume ref : connectez-vous avec dduck / Donald-Duck-2026.
ref), et non celle de l’application : l’identifiant (1) et le mot de passe ne sont saisis que chez TOSIAM.TOSIAM renvoie aussitôt le navigateur vers l’application avec la réponse SAML, par un formulaire envoyé automatiquement. La page « Profil » montre ce que l’assertion contenait :
transient, son format et l’IdP qui l’a signée (2), et la déconnexion (3).Si l’utilisateur a déjà une session TOSIAM, par exemple ouverte par une autre application, TOSIAM ne redemande rien : c’est l’authentification unique.
Étape 6 : se déconnecter#
« Se déconnecter » ferme la session de l’application, puis envoie le navigateur chez TOSIAM avec une demande de déconnexion (LogoutRequest). TOSIAM ferme sa session et renvoie une réponse signée à /saml/slo, dont l’application vérifie la signature, l’émetteur et la demande d’origine. Une réponse sans signature est refusée.
À la connexion suivante, TOSIAM redemande le mot de passe.
Les formats de NameID#
| Format | Valeur | Quand l’utiliser |
|---|---|---|
transient | Opaque, nouvelle à chaque connexion | L’application reconnaît l’utilisateur par un attribut (ici uid) : rien ne permet de suivre l’utilisateur d’une connexion à l’autre par le NameID |
persistent | Opaque, la même à chaque connexion pour cette application, différente pour chaque application | L’application garde ses propres comptes et les relie au NameID ; TOSIAM enregistre le lien entre le compte et l’application |
emailAddress, unspecified | Une valeur lisible (e-mail, identifiant), si l’IdP associe ce format à un attribut du profil (« Mappage des valeurs d’ID de nom » : emailAddress=mail par défaut, rien pour unspecified) | Applications qui l’exigent ; la valeur est la même pour toutes les applications |
L’application demande un format dans sa demande et dans ses métadonnées ; TOSIAM refuse un format que l’IdP ne propose pas.
En production#
- HTTPS partout, et une clé de signature propre à l’IdP, jamais la clé
testde la QuickStart. - Si TOSIAM doit vérifier qui envoie les demandes : une clé pour l’application, des demandes signées (
AuthnRequestsSigned="true"dans ses métadonnées), et, sur l’IdP, « Requête d’authentification » activé dans le groupe « Signature de la demande/réponse » (WantAuthnRequestsSigned). - Une session d’application partagée (base, cache) si l’application tourne sur plusieurs serveurs : le cache des demandes envoyées (
InResponseTo) doit l’être aussi. - Quand la clé de signature de l’IdP change, ses métadonnées enregistrées gardent l’ancien certificat : il faut les mettre à jour dans TOSIAM, puis donner le nouveau certificat à l’application (qui relit les métadonnées à son redémarrage), idéalement avant le changement de clé.
En cas de problème#
| Symptôme | Cause probable |
|---|---|
| « TOSIAM indisponible » après « Se connecter avec TOSIAM » | TOSIAM arrêté, ou fournisseur d’identité absent : relancez ./up.sh |
up.sh : « TOSIAM n’a pas pu préparer le fournisseur d’identité … Unable to find certificate by cert alias “test” » | Le serveur n’est pas une QuickStart : son keystore n’a pas de clé test |
| « Connexion refusée … Invalid signature » après une reconstruction de la QuickStart | La clé test a changé, mais l’IdP enregistré garde l’ancien certificat, ou l’application, restée démarrée, garde celui qu’elle a lu à sa première connexion : ./delete.sh puis ./up.sh |
| « Connexion refusée … No valid subject confirmation found » | Assertion expirée : horloges de TOSIAM et de l’application trop éloignées (plus de 5 secondes d’écart) |
| « Connexion refusée … InResponseTo » | Réponse rejouée, demande trop ancienne, ou application redémarrée entre la demande et la réponse : relancez la connexion depuis l’accueil |
Erreur 500 chez TOSIAM, journal Federation : « Identity provider does not support name identifier format » | TOSIAM antérieur à la 3.38.0, avec un IdP créé depuis le modèle (TOS-1750, corrigé en 3.38.0) |
| L’assertion ne contient que le NameID | Pas de correspondance d’attributs (attributeMap) sur le fournisseur de services ni sur l’IdP |
Pour aller plus loin#
- Qu’est-ce que SAML 2.0 ? : acteurs, bindings, assertion, métadonnées.
- TOSIAM dans l’autre rôle, fournisseur de services d’un IdP externe : les nœuds SAML 2.0 des graphes d’authentification.
- Les commandes de fédération de
ssoadm: référence des commandes.
Mis à jour le