SAML 2.0: jednotné přihlášení pomocí XML

SAML 2.0 je standard pro jednotné přihlášení (SSO), ve kterém si poskytovatel identity a aplikace vyměňují podepsané XML zprávy. Používají ho firemní systémy, univerzitní federace eduID.cz i státní Identita občana. Kapitola ukazuje průběh přihlášení, požadavek AuthnRequest, odpověď s asercí, metadata, ladění zpráv a bezpečnostní kontroly.

Autor: Aktualizováno

Co je SAML

SAML (Security Assertion Markup Language) je standard organizace OASIS; verze 2.0 z roku 2005 se používá dodnes. Popisuje, jak si dvě strany bezpečně předají informaci o přihlášeném uživateli:

  • Poskytovatel identity (IdP) — ověří uživatele (heslo, druhý faktor, eObčanka) a vydá o tom podepsané prohlášení. Příklady: Microsoft Entra ID, Okta, Keycloak, Shibboleth IdP na univerzitě, Národní identitní autorita.
  • Poskytovatel služby (SP) — aplikace, do které se uživatel přihlašuje. Heslo nikdy nevidí, věří podepsanému prohlášení od IdP.
  • Aserce (assertion) — samotné XML prohlášení: „uživatel X se u mě v 8:15 přihlásil heslem, jeho e-mail je … a platí to pro službu Y po dobu 5 minut“.

Všechny zprávy jsou XML ve dvou jmenných prostorech: protokol (urn:oasis:names:tc:SAML:2.0:protocol, prefix samlp) a aserce (urn:oasis:names:tc:SAML:2.0:assertion, prefix saml). Důvěru zajišťuje elektronický podpis XML.

Průběh přihlášení

Nejčastější scénář je přihlášení zahájené u služby (SP-initiated Web Browser SSO):

  1. Uživatel otevře chráněnou stránku služby a není přihlášený.
  2. Služba vytvoří AuthnRequest a přesměruje prohlížeč na přihlašovací adresu IdP.
  3. IdP uživatele ověří — případně ho pozná podle existující relace a nic nechce.
  4. IdP vrátí stránku se skrytým formulářem obsahujícím SAMLResponse s podepsanou asercí. Podepsaná může být i celá odpověď.
  5. Prohlížeč formulář automaticky odešle na adresu služby (Assertion Consumer Service).
  6. Služba odpověď ověří, založí vlastní relaci a pošle uživatele na původní stránku (podle RelayState).

Server služby a server IdP spolu při tom přímo nekomunikují — všechny zprávy nese prohlížeč. Služba proto musí ověřit požadované podpisy a všechny podmínky profilu. U vazby HTTP-POST musí být doručené aserce podepsané; samotný podpis obálky není podle tohoto profilu náhradou podpisu aserce.

Požadavek: AuthnRequest

AuthnRequest
<samlp:AuthnRequest
    xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
    xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
    ID="_a1b2c3d4e5f6"
    Version="2.0"
    IssueInstant="2026-09-29T08:15:00Z"
    Destination="https://idp.example.cz/sso"
    AssertionConsumerServiceURL="https://sluzba.example.cz/saml/acs"
    ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST">
  <saml:Issuer>https://sluzba.example.cz/saml</saml:Issuer>
  <samlp:NameIDPolicy Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"
                      AllowCreate="true"/>
</samlp:AuthnRequest>
  • ID musí být jedinečné a nesmí začínat číslicí (je to typ xs:ID) — proto ta podtržítka.
  • Issuer je entityID služby, jak ho IdP zná z metadat.
  • AssertionConsumerServiceURL a ProtocolBinding říkají, kam a jak má IdP odpověď poslat.
  • NameIDPolicy žádá o formát identifikátoru uživatele — trvalý pseudonym (persistent), jednorázový (transient) nebo e-mail.

Odpověď a aserce

Response s asercí
<samlp:Response
    xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
    xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
    ID="_r9f8e7d6" Version="2.0" IssueInstant="2026-09-29T08:15:04Z"
    Destination="https://sluzba.example.cz/saml/acs"
    InResponseTo="_a1b2c3d4e5f6">
  <saml:Issuer>https://idp.example.cz</saml:Issuer>
  <samlp:Status>
    <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
  </samlp:Status>

  <saml:Assertion ID="_x5y6z7" Version="2.0" IssueInstant="2026-09-29T08:15:04Z">
    <saml:Issuer>https://idp.example.cz</saml:Issuer>
    <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">…</ds:Signature>

    <saml:Subject>
      <saml:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">a7c1e0f4b2</saml:NameID>
      <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
        <saml:SubjectConfirmationData InResponseTo="_a1b2c3d4e5f6"
            Recipient="https://sluzba.example.cz/saml/acs"
            NotOnOrAfter="2026-09-29T08:20:04Z"/>
      </saml:SubjectConfirmation>
    </saml:Subject>

    <saml:Conditions NotBefore="2026-09-29T08:14:04Z" NotOnOrAfter="2026-09-29T08:20:04Z">
      <saml:AudienceRestriction>
        <saml:Audience>https://sluzba.example.cz/saml</saml:Audience>
      </saml:AudienceRestriction>
    </saml:Conditions>

    <saml:AuthnStatement AuthnInstant="2026-09-29T08:15:02Z" SessionIndex="_s42">
      <saml:AuthnContext>
        <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef>
      </saml:AuthnContext>
    </saml:AuthnStatement>

    <saml:AttributeStatement>
      <saml:Attribute Name="urn:oid:1.3.6.1.4.1.5923.1.1.1.6" FriendlyName="eduPersonPrincipalName"
          NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
        <saml:AttributeValue>jana.novakova@example.cz</saml:AttributeValue>
      </saml:Attribute>
      <saml:Attribute Name="urn:oid:0.9.2342.19200300.100.1.3" FriendlyName="mail"
          NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
        <saml:AttributeValue>jana@example.cz</saml:AttributeValue>
      </saml:Attribute>
    </saml:AttributeStatement>
  </saml:Assertion>
</samlp:Response>
  • Status — výsledek. Kromě Success se vrací například Requester, Responder nebo AuthnFailed.
  • Subject — kdo je přihlášený (NameID). Metoda bearer znamená, že aserce platí pro toho, kdo ji doručí; SubjectConfirmationData proto omezuje, na jakou adresu (Recipient), do kdy a jako odpověď na který požadavek ji lze doručit.
  • Conditions — časová platnost a pro jakou službu aserce platí (Audience).
  • AuthnStatement — kdy a jak se uživatel ověřil; SessionIndex se hodí pro odhlášení.
  • AttributeStatement — atributy uživatele. Ve federacích se pojmenovávají identifikátory OID a čitelné jméno je jen v FriendlyName.

Požadavky na podpis určuje použitý profil a vazba. U Web Browser SSO přes HTTP-POST musí být aserce podepsané; podepsaná může být navíc i celá odpověď. Aserce může být také zašifrovaná (EncryptedAssertion, podle standardu XML Encryption).

Vazby: jak zprávy cestují

Vazba (binding)Jak zpráva putujePoužití
HTTP-Redirectparametr SAMLRequest v URL: DEFLATE, Base64, URL kódování; podpis v parametru Signaturekrátké požadavky (AuthnRequest, odhlášení)
HTTP-POSTskrytý formulář, který prohlížeč automaticky odešle; zpráva v Base64odpovědi s aserci (jsou dlouhé a podepsané uvnitř XML)
HTTP-Artifactprohlížečem jde jen krátký odkaz, zprávu si SP vyzvedne přímo u IdP přes SOAPkdyž aserce nesmí projít prohlížečem
SOAPpřímé volání server–servervyzvednutí artefaktu, dotazy na atributy
HTTP-POST: formulář od IdP
<!-- Stránka, kterou vrátí IdP; prohlížeč formulář hned sám odešle -->
<form method="post" action="https://sluzba.example.cz/saml/acs">
  <input type="hidden" name="SAMLResponse" value="PHNhbWxwOlJlc3BvbnNlIHhtbG5z…"/>
  <input type="hidden" name="RelayState" value="/objednavky"/>
</form>

Metadata

Než spolu IdP a služba začnou komunikovat, vymění si metadata — XML soubor, který popisuje entitu: její entityID, adresy endpointů, podporované vazby a certifikáty pro podpis a šifrování.

Metadata služby (SP)
<md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata"
    entityID="https://sluzba.example.cz/saml">
  <md:SPSSODescriptor
      protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"
      AuthnRequestsSigned="true" WantAssertionsSigned="true">
    <md:KeyDescriptor use="signing">
      <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
        <ds:X509Data><ds:X509Certificate>MIIC…</ds:X509Certificate></ds:X509Data>
      </ds:KeyInfo>
    </md:KeyDescriptor>
    <md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</md:NameIDFormat>
    <md:AssertionConsumerService index="0" isDefault="true"
        Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
        Location="https://sluzba.example.cz/saml/acs"/>
  </md:SPSSODescriptor>
</md:EntityDescriptor>

Federace jako eduID.cz publikují metadata všech členů v jednom podepsaném souboru, který si služby pravidelně stahují. Když IdP vymění certifikát a služba má stará metadata, přihlášení přestane fungovat — to je jedna z nejčastějších provozních chyb.

SAML v Česku

  • Identita občana (NIA) — Národní identitní autorita zprostředkovává přihlášení eObčankou, bankovní identitou nebo mobilním klíčem eGovernmentu. Kvalifikovaní poskytovatelé služeb se k ní připojují přes SAML 2.0 (vazba HTTP-POST) a úroveň záruky ověření požadují podle pravidel eIDAS. Metadata NIA jsou veřejná na adrese https://nia.identitaobcana.cz/fpsts/FederationMetadata/2007-06/FederationMetadata.xml.
  • eduID.cz — akademická federace provozovaná sdružením CESNET. Univerzity v ní mají poskytovatele identity (typicky Shibboleth), knihovny, časopisy a e-learning jsou služby. Přes eduGAIN se propojuje s federacemi v zahraničí.
  • Firemní SSO — většina podnikových aplikací (Salesforce, Atlassian, SAP a další) umí SAML s Microsoft Entra ID, Okta nebo Keycloak.

Ladění: jak zprávu přečíst

Zprávy v prohlížeči nejsnáz zachytíš rozšířením SAML-tracer (Firefox, Chrome), které je rovnou dekóduje. Ručně je potřeba rozlišit vazbu:

Dekódování v terminálu
# HTTP-POST: jen Base64
echo "$SAMLResponse" | base64 --decode | xmllint --format -

# HTTP-Redirect: URL dekódování, Base64 a raw DEFLATE (bez hlavičky zlib)
python3 -c 'import sys,zlib,base64,urllib.parse as u;
print(zlib.decompress(base64.b64decode(u.unquote(sys.argv[1])), -15).decode())' "$SAMLRequest"

Totéž zvládneš v prohlížeči nástroji Base64 a Deflate. Výsledek vlož do formátovače — ale podepsanou zprávu, kterou chceš dál odeslat, nikdy nepřeformátovávej: změna bílých znaků v podepsaném elementu podpis rozbije.

Bezpečnost: co musí služba ověřit

Co SP musí zkontrolovatProč
podpisy požadované profilem; u HTTP-POST podpis aserce klíčem z důvěryhodných metadat IdPpodpis obálky sám nenahrazuje povinný podpis aserce
že podepsaný element je ten, ze kterého čteš dataobrana proti XML Signature Wrapping
Issuer, Audience a Recipient / Destinationaserce pro jinou službu se nesmí dát použít u tebe
NotBefore a NotOnOrAfter (s malou tolerancí hodin)prošlá aserce je neplatná
InResponseTo proti odeslaným požadavkům a jednorázovost IDobrana proti opakovanému použití (replay)
parser bez DTD a externích entitodpověď je XML od klienta — riziko XXE

Nejzákeřnější je XML Signature Wrapping: útočník vezme platně podepsanou odpověď, podepsanou aserci ponechá (podpis sedí), ale vloží vedle ní vlastní aserci s jiným uživatelem. Pokud knihovna ověří podpis jednoho elementu a data čte z jiného — třeba z prvního nalezeného přes //Assertion — útočník se přihlásí jako kdokoli. Proto nepiš vlastní zpracování SAML, ale použij udržovanou knihovnu (například Shibboleth SP, OneLogin php-saml a python3-saml, Sustainsys.Saml2 pro .NET, Spring Security SAML) a pravidelně ji aktualizuj. Podrobnosti o parserech najdeš v kapitole o útoku XXE.

SAML, nebo OpenID Connect?

SAML 2.0OpenID Connect
Formát zprávXML, podpis XMLDSigJSON, token JWT
Vznik2005, OASIS2014, OpenID Foundation (nad OAuth 2.0)
Přenospřesměrování a formuláře v prohlížečipřesměrování a volání REST API
Mobilní a SPA aplikacenepohodlnénavržené pro ně
Typické nasazenífiremní SSO, univerzitní federace, státní správapřihlášení přes Google, Apple, Microsoft, nové aplikace

Pro nové aplikace, hlavně mobilní a SPA, se dnes obvykle volí OpenID Connect. SAML ale zůstává standardem všude, kde už federace a IdP existují — v podnicích, na univerzitách i ve státní správě. Rozhodující je podpora protokolu, průběh přihlášení a pravidla ověřování, nikoli jen volba XML nebo JSON. Obecné srovnání formátů najdeš v kapitole XML vs JSON.

Podpisy se kontrolují podle konkrétní vazby

Web Browser SSO přes HTTP-POST požaduje podpis jednotlivých asercí. U HTTP-Artifact platí jiná pravidla, protože služba zprávu získává přímou komunikací s poskytovatelem identity. Podpis vždy ověřuj podle SAML Profiles, oddílů 4.1.4.4 a 4.1.4.5, ne podle toho, který element náhodou obsahuje Signature. Nejdřív ověř podpis a podmínky; teprve z ověřené aserce založ uživatelskou relaci.