SAML 2.0 reste le protocole de fédération dominant en entreprise. Même si OIDC est plus moderne, la majorité des applications SaaS enterprise (Salesforce, ServiceNow, Workday...) supportent SAML en premier. Si vous intégrez des applications d'entreprise, vous rencontrerez SAML. Ce guide vous donne les clés pour le comprendre, le configurer et le déboguer.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »Ce guide vous explique SAML 2.0, le protocole de fédération dominant dans les grandes entreprises. À la fin, vous saurez :
- Comprendre pourquoi SAML reste omniprésent malgré OIDC
- Distinguer les flux SP-initiated et IdP-initiated
- Configurer les assertions, signatures et mapping d'attributs
- Diagnostiquer les erreurs SAML les plus courantes
Prérequis : avoir lu OpenID Connect.
Pourquoi SAML existe encore
Section intitulée « Pourquoi SAML existe encore »SAML 2.0 date de 2005. Pourquoi est-il encore partout ?
Réponse courte : parce que les grandes applications enterprise (Salesforce, ServiceNow, Workday, SAP...) le supportent depuis des années, et qu'il fonctionne.
Quand utiliser SAML
Section intitulée « Quand utiliser SAML »Le choix ne vous appartient qu'à moitié : dans la plupart des intégrations, c'est l'application cible qui impose son protocole. Ce tableau sert donc surtout à trancher les cas où vous avez réellement la main, typiquement une application que vous développez. Retenez la logique générale : SAML pour l'existant enterprise et le B2B, OIDC pour tout ce qui est neuf, OAuth 2.0 dès qu'il s'agit d'autoriser un accès API plutôt que d'authentifier une personne.
| Situation | Protocole recommandé |
|---|---|
| L'application ne supporte que SAML | SAML |
| Intégration B2B avec un partenaire SAML | SAML |
| Nouvelle application web/mobile | OIDC |
| API à sécuriser | OAuth 2.0 |
SAML vs OIDC : différences clés
Section intitulée « SAML vs OIDC : différences clés »Comprendre ces différences vous aide à choisir le bon protocole selon votre contexte. SAML reste incontournable en entreprise, tandis qu'OIDC domine les architectures modernes.
| Aspect | SAML | OIDC |
|---|---|---|
| Année | 2005 | 2014 |
| Format | XML | JSON/JWT |
| Taille des messages | Verbeux (~5-15 KB) | Compact (~1-2 KB) |
| Signature | XML-DSig + certificats | JWS (signature JWT) |
| Chiffrement | XML-Enc (optionnel) | JWE (optionnel) |
| Configuration | Échange de fichiers metadata | Discovery endpoint |
| Mobile/SPA | Difficile | Natif |
| Enterprise legacy | Excellent support | Variable |
| Debugging | Complexe (XML, signatures) | Simple (jwt.io, JSON) |
Les acteurs SAML
Section intitulée « Les acteurs SAML »Trois acteurs interviennent dans chaque échange SAML. Connaître leur rôle est essentiel pour déboguer les problèmes de fédération.
| Acteur | Rôle | Équivalent OIDC |
|---|---|---|
| Identity Provider (IdP) | Authentifie l'utilisateur, émet les assertions | OpenID Provider |
| Service Provider (SP) | Application qui consomme les assertions | Relying Party |
| Principal | L'utilisateur qui s'authentifie | End-User |
Les deux modes SSO
Section intitulée « Les deux modes SSO »SAML définit deux points de départ possibles pour une connexion, et ils ne se valent pas en matière de sécurité. La différence tient à un seul détail : l'existence ou non d'une AuthnRequest émise par le Service Provider. Quand elle existe, le SP peut vérifier que la réponse reçue correspond bien à une demande qu'il a lui-même initiée, via l'attribut InResponseTo. Sans elle, cette vérification est impossible.
SP-initiated (recommandé)
Section intitulée « SP-initiated (recommandé) »L'utilisateur commence par l'application (Service Provider).
-
Accès à l'application
L'utilisateur tente d'accéder à https://salesforce.example.com
-
Génération de l'AuthnRequest
Le SP génère une demande d'authentification SAML (AuthnRequest).
-
Redirection vers l'IdP
Le navigateur est redirigé vers l'IdP avec l'AuthnRequest.
-
Authentification
L'IdP authentifie l'utilisateur (login, MFA...).
-
Génération de l'assertion
L'IdP crée une assertion SAML signée contenant l'identité.
-
Retour au SP (POST)
Le navigateur envoie l'assertion au SP (généralement via HTTP-POST).
-
Validation et session
Le SP valide la signature et crée une session pour l'utilisateur.
Avantages :
- L'application contrôle le flux
- Protection CSRF native (le SP génère un ID de requête)
IdP-initiated
Section intitulée « IdP-initiated »L'utilisateur commence par le portail IdP.
-
Accès au portail IdP
L'utilisateur accède au portail enterprise (ex: Okta dashboard).
-
Clic sur l'application
L'utilisateur clique sur l'icône de l'application.
-
Génération directe de l'assertion
L'IdP génère une assertion SAML sans AuthnRequest préalable.
-
Envoi au SP
L'assertion est envoyée directement au SP.
-
Validation et session
Le SP valide et crée la session.
Risques :
- Pas d'AuthnRequest = pas de
InResponseToà valider - Risque de CSRF si le
RelayStaten'est pas vérifié
L'assertion SAML
Section intitulée « L'assertion SAML »Une assertion SAML est un document XML signé qui contient :
- L'identité de l'utilisateur (NameID)
- Les attributs (email, groupes, rôles...)
- Les conditions de validité (dates, audience)
- La signature de l'IdP
Structure simplifiée
Section intitulée « Structure simplifiée »Voici une assertion réduite à ses éléments porteurs de sens ; en production elle fait plusieurs kilo-octets, dont l'essentiel est occupé par le bloc de signature encodé en base64.
<saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_abc123" IssueInstant="2024-02-06T10:00:00Z">
<!-- Qui a émis l'assertion --> <saml:Issuer>https://idp.example.com</saml:Issuer>
<!-- Signature XML --> <ds:Signature>...</ds:Signature>
<!-- Subject : l'utilisateur authentifié --> <saml:Subject> <saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"> alice@example.com </saml:NameID> </saml:Subject>
<!-- Conditions de validité --> <saml:Conditions NotBefore="2024-02-06T10:00:00Z" NotOnOrAfter="2024-02-06T10:05:00Z"> <saml:AudienceRestriction> <saml:Audience>https://salesforce.example.com</saml:Audience> </saml:AudienceRestriction> </saml:Conditions>
<!-- Contexte d'authentification --> <saml:AuthnStatement AuthnInstant="2024-02-06T10:00:00Z"> <saml:AuthnContext> <saml:AuthnContextClassRef> urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport </saml:AuthnContextClassRef> </saml:AuthnContext> </saml:AuthnStatement>
<!-- Attributs --> <saml:AttributeStatement> <saml:Attribute Name="email"> <saml:AttributeValue>alice@example.com</saml:AttributeValue> </saml:Attribute> <saml:Attribute Name="groups"> <saml:AttributeValue>developers</saml:AttributeValue> <saml:AttributeValue>admins</saml:AttributeValue> </saml:Attribute> </saml:AttributeStatement>
</saml:Assertion>Éléments clés
Section intitulée « Éléments clés »Ce sont les six balises que vous regarderez en priorité lors d'un dépannage. Trois d'entre elles décident à elles seules de l'acceptation ou du rejet : Conditions pour la fenêtre temporelle et le destinataire, Signature pour l'authenticité, NameID pour la correspondance avec un compte existant côté application.
| Élément | Description |
|---|---|
Issuer | URL de l'IdP qui a émis l'assertion |
NameID | Identifiant principal de l'utilisateur |
Conditions | Période de validité, audience autorisée |
AuthnStatement | Preuve de l'authentification |
AttributeStatement | Attributs additionnels (email, groupes...) |
Signature | Signature XML de l'IdP |
Signatures et certificats
Section intitulée « Signatures et certificats »SAML utilise XML-DSig pour signer les assertions (et optionnellement les chiffrer).
Ce qui est signé
Section intitulée « Ce qui est signé »Une réponse SAML contient deux enveloppes signables : la Response et l'Assertion qu'elle transporte. Signer la seule Response laisse la porte ouverte aux attaques par substitution d'assertion, où un attaquant remplace le contenu utile en conservant l'enveloppe signée. La signature de l'assertion est donc obligatoire, celle de la réponse fortement recommandée.
| Élément | Signé par |
|---|---|
| Assertion | L'IdP (obligatoire) |
| Response | L'IdP (recommandé) |
| AuthnRequest | Le SP (optionnel) |
Gestion des certificats
Section intitulée « Gestion des certificats »Le certificat de signature de l'IdP est copié dans la configuration de chaque Service Provider. C'est ce qui rend sa rotation délicate : le changer d'un côté casse tous les autres tant qu'ils n'ont pas récupéré le nouveau. La parade consiste à publier les deux certificats simultanément dans les metadata avant de basculer la signature.
Vérification côté SP
Section intitulée « Vérification côté SP »Le SP doit :
- Obtenir le certificat public de l'IdP (via metadata ou import manuel)
- Valider la signature de l'assertion
- Valider la chaîne de certificats (optionnel selon la config)
Metadata : l'échange de configuration
Section intitulée « Metadata : l'échange de configuration »Les fichiers metadata contiennent la configuration SAML d'un IdP ou d'un SP.
Metadata IdP
Section intitulée « Metadata IdP »Le metadata d'un IdP publie deux informations que le SP ne peut pas deviner : le certificat public qui servira à valider les signatures, et l'URL du service SingleSignOnService vers laquelle rediriger l'utilisateur.
<EntityDescriptor entityID="https://idp.example.com"> <IDPSSODescriptor> <KeyDescriptor use="signing"> <ds:KeyInfo> <ds:X509Data> <ds:X509Certificate>MIIC...</ds:X509Certificate> </ds:X509Data> </ds:KeyInfo> </KeyDescriptor> <SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://idp.example.com/sso"/> </IDPSSODescriptor></EntityDescriptor>Metadata SP
Section intitulée « Metadata SP »Côté SP, l'élément déterminant est l'AssertionConsumerService : c'est l'URL exacte où l'IdP postera l'assertion, et la moindre différence de casse ou de slash final provoque un rejet. L'entityID déclaré ici doit par ailleurs correspondre exactement à la valeur que l'IdP place dans l'AudienceRestriction.
<EntityDescriptor entityID="https://salesforce.example.com"> <SPSSODescriptor> <KeyDescriptor use="signing"> <ds:KeyInfo> <ds:X509Data> <ds:X509Certificate>MIID...</ds:X509Certificate> </ds:X509Data> </ds:KeyInfo> </KeyDescriptor> <AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://salesforce.example.com/saml/acs" index="0"/> </SPSSODescriptor></EntityDescriptor>Échange de metadata
Section intitulée « Échange de metadata »L'échange est bidirectionnel : chaque partie doit connaître l'autre, et une configuration à sens unique produit une erreur au moment du retour vers l'application. Quand l'IdP publie une URL de metadata plutôt qu'un fichier, préférez-la : le SP recharge alors le certificat automatiquement lors des rotations.
-
Exporter le metadata de l'IdP
-
Importer dans le SP (ou donner l'URL du metadata)
-
Exporter le metadata du SP
-
Importer dans l'IdP (créer un "realm" ou "application")
-
Configurer le mapping d'attributs
Mapping d'attributs
Section intitulée « Mapping d'attributs »Les attributs SAML ne sont pas standardisés. Chaque vendor utilise ses propres noms.
NameID : l'identifiant principal
Section intitulée « NameID : l'identifiant principal »Le NameID est la clé sur laquelle le SP fait correspondre l'assertion à un compte local, et son format doit être identique des deux côtés. L'adresse e-mail est le choix le plus répandu mais aussi le plus fragile : elle change quand la personne se marie ou change de service, et l'utilisateur perd alors l'accès à son compte. Le format persistent évite ce problème en fournissant un identifiant opaque et stable par couple utilisateur/application.
| Format | Valeur | Usage |
|---|---|---|
emailAddress | alice@example.com | Le plus courant |
persistent | ID opaque stable | Recommandé pour la sécurité |
transient | ID temporaire | Sessions anonymes |
unspecified | Quelconque | À éviter |
Mapping des attributs courants
Section intitulée « Mapping des attributs courants »Trois correspondances reviennent dans presque toutes les intégrations. Elles illustrent le même travail : la colonne de gauche est le nom imposé par l'application, celle du milieu le nom que porte l'attribut dans votre annuaire, et le mapper configuré sur l'IdP fait la traduction au moment d'émettre l'assertion. Un attribut absent de cette configuration ne figurera tout simplement pas dans l'AttributeStatement.
| Ce que le SP attend | Ce que l'IdP a | Solution |
|---|---|---|
User.Email | email | Mapper email → User.Email |
memberOf | groups | Mapper groups → memberOf |
firstName | givenName | Mapper givenName → firstName |
Dépannage SAML
Section intitulée « Dépannage SAML »Déboguer SAML est plus ingrat qu'OIDC parce que les messages transitent par des redirections du navigateur et non par des appels serveur à serveur : ils n'apparaissent dans aucun journal applicatif. La méthode consiste donc toujours à capturer l'échange dans le navigateur, à décoder l'assertion, puis à comparer son contenu à ce que le SP attend.
Outils de diagnostic
Section intitulée « Outils de diagnostic »Ces quatre sources se complètent : les deux premières donnent le contenu réel de l'échange, les deux dernières le verdict de chaque partie. Attention avec les décodeurs en ligne : une assertion contient des données d'identité, ne collez pas une assertion de production sur un service tiers.
| Outil | Usage |
|---|---|
| SAML-tracer (extension navigateur) | Capturer les requêtes/réponses SAML |
| samltool.com | Décoder, valider, générer des assertions |
| Keycloak logs | Erreurs côté IdP |
| Logs applicatifs | Erreurs côté SP |
Erreurs courantes
Section intitulée « Erreurs courantes »Les six messages ci-dessous représentent la quasi-totalité des échecs constatés en intégration. Ils partagent un point commun utile au diagnostic : ils viennent tous d'un désaccord de configuration entre l'IdP et le SP, pas d'un défaut du protocole. Repérez le message exact dans les journaux du SP, la colonne du milieu vous dit de quel côté chercher.
| Symptôme | Cause probable | Solution |
|---|---|---|
Invalid signature | Certificat mal importé, mauvais certificat | Ré-importer le certificat de l'IdP |
Assertion expired | Clock skew (décalage d'horloge) | Synchroniser NTP sur tous les serveurs |
Invalid audience | Audience ne correspond pas à l'entityID du SP | Vérifier la config côté IdP |
ACS URL mismatch | L'URL de retour ne correspond pas | Vérifier AssertionConsumerService dans les metadata |
Missing attribute | Attribut non mappé | Configurer le mapper côté IdP |
NameID format mismatch | Le SP attend un format différent | Aligner les formats NameID |
Checklist de dépannage
Section intitulée « Checklist de dépannage »Suivez ces six vérifications dans l'ordre : elles vont du plus général au plus précis, et chacune élimine une famille de causes. La première est incontournable, sans capture du trafic vous en serez réduit aux hypothèses.
-
Capturer le trafic avec SAML-tracer
-
Décoder la Response sur samltool.com
-
Vérifier les timestamps (NotBefore, NotOnOrAfter)
-
Vérifier l'Audience
-
Valider la signature (certificat correct ?)
-
Vérifier les attributs présents dans l'assertion
Sécurité SAML
Section intitulée « Sécurité SAML »La sécurité de SAML repose entièrement sur la validation faite par le Service Provider. L'IdP a beau signer correctement, une bibliothèque SP qui accepte une assertion sans vérifier sa signature, son audience ou sa fenêtre de validité annule toute la protection. Historiquement, la plupart des vulnérabilités SAML publiées portaient sur des défauts de validation côté SP, pas sur le protocole.
Risques et mitigations
Section intitulée « Risques et mitigations »Ce tableau se lit comme une liste de contrôles à confirmer sur votre implémentation, pas comme un catalogue théorique. Pour chaque ligne, la question à poser à l'équipe qui exploite le SP est simple : cette vérification est-elle activée, et l'avez-vous testée en la faisant échouer volontairement ?
| Risque | Mitigation |
|---|---|
| Signature bypass | Toujours valider la signature de l'assertion ET de la response |
| XML injection | Parser XML sécurisé, désactiver les entity references |
| Replay attack | Vérifier InResponseTo, tracker les assertion IDs consommées |
| IdP-initiated CSRF | Valider RelayState, préférer SP-initiated |
| Assertion interception | HTTPS obligatoire, chiffrement optionnel |
Bonnes pratiques
Section intitulée « Bonnes pratiques »Ces cinq réglages sont ceux à appliquer par défaut sur toute nouvelle intégration. Le plus souvent négligé est la durée de validité : une assertion valable une heure reste rejouable pendant une heure si le SP ne mémorise pas les identifiants déjà consommés.
- Signez les assertions ET les responses
- Chiffrez les assertions si elles contiennent des données sensibles
- Validez l'audience (
AudienceRestriction) - Limitez la durée de validité des assertions (< 5 min)
- Utilisez SP-initiated quand possible
Erreurs fréquentes
Section intitulée « Erreurs fréquentes »Là où le tableau de dépannage listait des messages d'erreur, celui-ci recense les défauts d'exploitation qui n'émettent aucune alerte tant que le SSO fonctionne. Ils se manifestent tous de la même façon : une panne brutale un matin, sans changement apparent la veille. La colonne de droite décrit à chaque fois une mesure préventive, à mettre en place avant l'incident.
| Erreur | Conséquence | Solution |
|---|---|---|
| Certificat expiré non détecté | SSO cassé | Alerting sur les dates d'expiration |
Pas de validation InResponseTo | Vulnérable au replay | Valider l'ID de la requête originale |
| Clock skew > 5 min | Assertions toujours rejetées | NTP sur tous les serveurs |
| Metadata pas à jour | Échecs intermittents | URL de metadata + refresh automatique |