Skip to content

SAML 2.0

  • SAML 2.0 Core
  • SAML 2.0 Bindings
  • SAML 2.0 Profiles
  • SAML 2.0 Metadata
  • W3C XML Signature (Exclusive Canonicalization, enveloped signatures)

ProtocolSoup runs a SAML identity provider and a SAML service provider as two distinct entities. Each has its own entityID, its own RSA signing key with a self-signed X.509 certificate, and its own metadata.

Role entityID (also its metadata location)
Identity provider {BASE_URL}/saml/idp/metadata
Service provider {BASE_URL}/saml/sp/metadata

Each entityID is the URL its metadata is published at (SAML Metadata Section 4.1.1). Neither role reads the other’s state. Each fetches the other’s metadata over HTTP and trusts only the signing certificate published there. A certificate carried in a message’s <ds:KeyInfo> is never trusted unless it matches that metadata.

Keys and certificates persist under {SHOWCASE_DATA_DIR}/saml/ (idp.key.pem, idp.cert.pem, sp.key.pem, sp.cert.pem). Without a data directory they are generated on each start.

Flow ID Name Description
sp_initiated_sso SP-Initiated SSO Service Provider starts the login flow
idp_initiated_sso IdP-Initiated SSO Identity Provider sends an unsolicited Response
single_logout Single Logout SP-initiated logout with signed LogoutRequest and LogoutResponse
idp_initiated_logout IdP-Initiated Single Logout The IdP, as session authority, logs the SP out (Profiles Section 4.4.3.3)
metadata Metadata Exchange SP/IdP metadata discovery and sharing
Path Methods Purpose
/saml/idp/metadata GET IdP EntityDescriptor (application/samlmetadata+xml)
/saml/idp/sso GET, POST SingleSignOnService (HTTP-Redirect, HTTP-POST)
/saml/idp/login POST Principal authentication; starts the IdP session and answers with the signed Response (Cancel answers AuthnFailed)
/saml/idp/initiate GET Start IdP-initiated SSO (optional RelayState)
/saml/idp/logout GET Start IdP-initiated Single Logout (session_id, binding)
/saml/idp/slo GET, POST SingleLogoutService (HTTP-Redirect, HTTP-POST); a LogoutResponse gets the outcome page
Path Methods Purpose
/saml/sp/metadata GET SP EntityDescriptor (application/samlmetadata+xml)
/saml/sp/login GET Start SP-initiated SSO (binding=redirect or post, optional RelayState, force_authn=true, is_passive=true)
/saml/sp/acs POST AssertionConsumerService (HTTP-POST only); answers with the outcome page
/saml/sp/logout GET Start SP-initiated Single Logout (session_id, binding)
/saml/sp/slo GET, POST SingleLogoutService (HTTP-Redirect, HTTP-POST); a LogoutResponse gets the outcome page
Path Methods Purpose
/saml/demo/sessions GET Current sessions held by the SP (sp) and the IdP (idp), so Looking Glass can pick one to log out

Looking Glass runs every SAML flow through the real endpoints above, in a popup, so the browser follows each HTTP-Redirect and HTTP-POST hop itself. The executor adds the Looking Glass session to the first URL as lg_session. Each role carries it on to the next endpoint it sends the user agent to, outside the signed query values (SAML Bindings Section 3.4.4.1 signs only SAMLRequest/SAMLResponse, RelayState and SigAlg) and outside the Destination attribute. The capture middleware and the roles’ events therefore record every real exchange.

The endpoint that receives the last message of a flow answers with an outcome page. That is the assertion consumer service for SSO, and the initiator’s SingleLogoutService for logout. The page shows:

  • the message as it arrived;
  • every check the receiving role ran, with its spec reference;
  • the session or status it produced.

When Looking Glass opened the window, the page also hands the outcome to it with postMessage. It addresses only the deployment’s own origin and the configured frontend origins (SHOWCASE_CORS_ORIGINS).

  • Enveloped XML signatures (SAML Core Section 5.4.1), RSA-SHA256, SHA-256 digests, and Exclusive Canonicalization (Section 5.4.3).
  • <ds:Signature> sits immediately after <saml:Issuer>. It holds a single <ds:Reference> whose URI is # plus the signed element’s ID (Section 5.4.2).
  • Verifiers reject transforms other than enveloped-signature and exclusive canonicalization (Section 5.4.4). They also reject <ds:Object> (Errata E91) and any ID declared more than once (Section 1.3.4).
  • Only the signed bytes are read after verification, which defeats XML Signature Wrapping.
  • The HTTP-Redirect binding carries no XML signature. The query string SAMLRequest|SAMLResponse=…&RelayState=…&SigAlg=… is signed, and verified over the received URL-encoded values (Bindings Section 3.4.4.1).

IdP, on an AuthnRequest

  • The signature verifies against the SP’s metadata. An unsigned request gets a SAML error Response with status Requester / RequestDenied, because the SP’s metadata declares AuthnRequestsSigned="true" (Metadata Section 2.4.4, Errata E7).
  • Destination is checked.
  • The AssertionConsumerServiceURL or AssertionConsumerServiceIndex must be an HTTP-POST endpoint in the SP’s metadata (Profiles Section 4.1.4.1).
  • An unsupported NameIDPolicy gets an error Response.

IdP, identifying the principal (Profiles Section 4.1.3.4)

  • The principal signs in once at the IdP. The IdP keeps an authentication session (the saml_idp_session cookie, 8 hours) and answers every later AuthnRequest, and IdP-initiated SSO, from it without asking for credentials. That is the single sign-on. The assertion’s AuthnInstant is the original sign-in.
  • ForceAuthn="true" makes the IdP ask for credentials again despite the session (Core Section 3.4.1).
  • IsPassive="true" succeeds only from a live session. Without one, or together with ForceAuthn, the IdP returns Responder / NoPassive.
  • Cancel at the sign-in page returns Responder / AuthnFailed (Profiles Section 4.1.3.5).
  • Single Logout ends the IdP session, so the next SSO asks for credentials (Core Section 3.7.3.2).

SP, on a Response (Profiles Sections 4.1.4.3 and 4.1.4.5)

  • Delivery over HTTP-POST only.
  • Response and assertion signatures are verified against the IdP’s metadata. The assertion must carry its own signature (WantAssertionsSigned="true").
  • Destination, Issuer (with Format omitted or entity) and Version are checked.
  • InResponseTo must match an outstanding AuthnRequest, and RelayState must equal the value sent with it.
  • At least one bearer SubjectConfirmation must have a matching Recipient, an unexpired NotOnOrAfter, no NotBefore and a matching InResponseTo.
  • Conditions must hold their time window, and every AudienceRestriction must include the SP.
  • An AuthnStatement with a SessionIndex must be present.
  • The assertion ID must not be a replay.
  • Clock skew is 3 minutes (SAML Core Errata E92).
  • Any failed check rejects the Response.

Single Logout

  • LogoutRequest and LogoutResponse must be signed on the front-channel bindings (Profiles Sections 4.4.3.1 and 4.4.3.4).
  • Issuer, Destination and NotOnOrAfter are checked.
  • A LogoutRequest from the SP must carry a SessionIndex (Section 4.4.4.1).
  • InResponseTo and RelayState must match the outstanding request.

Limits

  • The bindings are HTTP-Redirect and HTTP-POST only; there is no Artifact or SOAP binding.
  • There is no EncryptedAssertion support.
  • The SP accepts unsolicited Responses.
  • RelayState longer than 80 bytes is refused (Bindings Sections 3.4.3 and 3.5.3).