TutorielGuides

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 ?.

  1. Navigateur vers Application (SP) « Se connecter avec TOSIAM »
  2. Application (SP) vers Navigateur Redirection vers TOSIAM avec une AuthnRequest
  3. Navigateur vers TOSIAM (IdP GET /SSORedirect/metaAlias/ref/exemple-saml-idp
  4. TOSIAM (IdP vers Navigateur Page de connexion XUI, puis formulaire auto-envoyé
  5. Navigateur vers Application (SP) POST /saml/acs : SAMLResponse (assertion signée)
  6. Application (SP) vers Navigateur Session de l’application, page « Profil »
L’application ne voit jamais le mot de passe : elle reçoit une assertion signée par TOSIAM, qu’elle vérifie avant d’ouvrir sa propre session.

Étape 1 : le vocabulaire de SAML#

Faites défiler le tableau
TermeDans l’exemple
Fournisseur d’identité (IdP) : connecte l’utilisateur et émet les assertionsTOSIAM, entité tosiam-exemple-saml-idp, royaume ref
Fournisseur de services (SP) : l’application qui fait confiance à l’IdPL’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 ensembleexemple-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 applicationFormat 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 :

bash
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) :

bash
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 ».

Console, menu Fédérations du royaume ref : tosiam-exemple-saml-idp, rôle IDP, hosted, dans un cercle ; tosiam-exemple-saml-application, rôle SP, remote, dans un cercle Console, menu Fédérations du royaume ref : tosiam-exemple-saml-idp, rôle IDP, hosted, dans un cercle ; tosiam-exemple-saml-application, rôle SP, remote, dans un cercle
Le royaume 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.
Console, fournisseur d'identité tosiam-exemple-saml-idp, onglet Contenu de l'assertion : clé de signature test ; liste de formats d'ID de nom, dont persistent et transient Console, fournisseur d'identité tosiam-exemple-saml-idp, onglet Contenu de l'assertion : clé de signature test ; liste de formats d'ID de nom, dont persistent et transient
La clé qui signe les assertions (1) et les formats de NameID que l’IdP accepte de produire (2).

É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) :

xml
<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) :

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 forme nom 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.
bash
ssoadm import-entity --realm ref --cot exemple-saml \
  --meta-data-file application-sp.xml --extended-data-file application-sp-ext.xml

Les mêmes réglages se retrouvent sur la page du fournisseur de services, dans la console :

Console, fournisseur de services tosiam-exemple-saml-application, onglet Contenu de l'assertion : Assertions signées true, Réponse de déconnexion signée true Console, fournisseur de services tosiam-exemple-saml-application, onglet Contenu de l'assertion : Assertions signées true, Réponse de déconnexion signée true
« Assertions signées », qui vient des métadonnées de l’application (1), et « Réponse de déconnexion signée », qui vient de la configuration étendue (2).
Console, fournisseur de services tosiam-exemple-saml-application, onglet Traitement de l'assertion : Mappage d'attributs mail=mail, cn=cn, uid=uid Console, fournisseur de services tosiam-exemple-saml-application, onglet Traitement de l'assertion : Mappage d'attributs mail=mail, cn=cn, uid=uid
L’onglet « Traitement de l’assertion » (1) et la correspondance des attributs envoyés à l’application (2).

É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) :

javascript
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 :

bash
./up.sh          # Windows : up.bat
Accueil de l'application SAML : Bienvenue, cette application ne gère aucun mot de passe, bouton Se connecter avec TOSIAM Accueil de l'application SAML : Bienvenue, cette application ne gère aucun mot de passe, bouton Se connecter avec TOSIAM
L’application n’a pas de formulaire de connexion : un seul bouton (1), qui envoie chez TOSIAM.

« 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.

Page de connexion XUI de TOSIAM : Connexion à TOSIAM, identifiant dduck, mot de passe, bouton Se connecter Page de connexion XUI de TOSIAM : Connexion à TOSIAM, identifiant dduck, mot de passe, bouton Se connecter
La page de connexion de TOSIAM (royaume 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 :

Profil de l'application SAML : attributs uid dduck, cn Donald, mail donald_duck@tosiam.io ; NameID transient, format urn:oasis:names:tc:SAML:2.0:nameid-format:transient, émetteur tosiam-exemple-saml-idp Profil de l'application SAML : attributs uid dduck, cn Donald, mail donald_duck@tosiam.io ; NameID transient, format urn:oasis:names:tc:SAML:2.0:nameid-format:transient, émetteur tosiam-exemple-saml-idp
Les attributs ajoutés par la correspondance du fournisseur de services (1), le sujet de l’assertion : NameID 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.

Application SAML : Vous êtes déconnecté, l'application et TOSIAM ont fermé leur session, bouton Accueil Application SAML : Vous êtes déconnecté, l'application et TOSIAM ont fermé leur session, bouton Accueil
La réponse de déconnexion de TOSIAM, signée, a été acceptée (1) : les deux sessions sont fermées.

À la connexion suivante, TOSIAM redemande le mot de passe.

Les formats de NameID#

Faites défiler le tableau
FormatValeurQuand l’utiliser
transientOpaque, nouvelle à chaque connexionL’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
persistentOpaque, la même à chaque connexion pour cette application, différente pour chaque applicationL’application garde ses propres comptes et les relie au NameID ; TOSIAM enregistre le lien entre le compte et l’application
emailAddress, unspecifiedUne 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é test de 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#

Faites défiler le tableau
SymptômeCause 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 QuickStartLa 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 NameIDPas de correspondance d’attributs (attributeMap) sur le fournisseur de services ni sur l’IdP

Pour aller plus loin#

Mis à jour le