24 February 2019

SAML 2.0

by mo


The security assertion markup language is an XML based protocol for completing authentication.

Each SAML transaction includes at least 3 parties.

  • Service Provider (SP)
  • User Agent
  • Identity Provider (IDP)

A benefit of using SAML 2.0 is that the identity provider (IDP) and the service provider (SP) do not need to be able to directly access one another. As long as the user agent can connect to both parties a SAML 2.0 transaction can be completed. The user agent is used to transport the messages between both the IDP and the SP.

This allows organizations to keep their IDP’s behind a VPN but still allow SAAS products to federate login to an organizations existing IDP solution .e.g Active Directory.

For the IDP and `SP. to communicate with one another there is some information that each party needs to know about the other in order to trust that the message originated from the actual party and that secrets are only readable by the intended party. For an introduction to public key crypto please read public key cryptography.

To establish trust, each party needs to exchange and entityID and public keys with one another. This information can be exchange through the SAML 2.0 Metadata. This metadata is typically hosted at a public location that can be shared with anyone.

Metadata

The metadata is an XML document that describes:

  • entityID: A unique identifier that identifies the party. Typically the uri of where the metadata document is hosted.
  • signing/encryption public keys: Usually in form of an x509 certificate.
  • IDP/SP elements: describe if the party can act as an IDP or SP or both.
  • endpoints: that can be used to transport specific types of messages.
  • attributes: that the party can share with the other about a specific subject.

Here’s an example of a minimal metadata that describes an IDP.

<?xml version="1.0"?>
<EntityDescriptor entityID="https://www.example.org/metadata" xmlns="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_afa7d243-a1af-44a9-9a9b-83ed35f537ba">
  <IDPSSODescriptor WantAuthnRequestsSigned="true" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
    <KeyDescriptor use="signing">
      <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
        <X509Data>
          <X509Certificate>x509 certificate</X509Certificate>
        </X509Data>
      </KeyInfo>
    </KeyDescriptor>
    <NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</NameIDFormat>
    <SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://www.example.org/session/new"/>
    <SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://www.example.org/session/new"/>
  </IDPSSODescriptor>
</EntityDescriptor>

The metadata above describes a few important things about this party.

Let’s break it down one section at a time.

The following section tells us entityID for this party.

<EntityDescriptor entityID="https://www.example.org/metadata">

This element tells us that this party can perform the functions of an identity provider.

<IDPSSODescriptor>

This element tells us that the key info referred to in the KeyDescriptor describes a signing key. Signing keys can be used for verifying signatures. The use can be either signing or encryption. If the use is omitted then the key can be used for both.

<KeyDescriptor use="signing">

The NameIDFormat tells us what types of identifiers this party is able to return to the SP to identify the user that signs in. Some common name id formats are email, persistent or transient identifiers. An example of a persistent identifier would be a UUID that identifies a user.

<NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</NameIDFormat>

The SingleSignOnService element is a required element for an IDP. It tells the SP the endpoint that they can direct the user agent to in order to initiate an authentication request (AuthnRequest). The Binding tells the SP how to encode the message so that the IDP can decode it.

This example describes a HTTP-Redirect binding. I’ll describe a few common types of bindings later in this post.

<SingleSignOnService 
  Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" 
  Location="https://www.example.org/session/new"
  />

Next let’s take a look at an example of an SP metadata.

<?xml version="1.0"?>
<EntityDescriptor entityID="https://www.example.com/metadata" xmlns="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_9fd49a06-ee79-49a2-ba29-ddd4e3950bd2" >
  <SPSSODescriptor AuthnRequestsSigned="true" WantAssertionsSigned="true" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
    <KeyDescriptor use="signing">
      <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
        <X509Data>
          <X509Certificate>x509 certificate</X509Certificate>
        </X509Data>
      </KeyInfo>
    </KeyDescriptor>
    <NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</NameIDFormat>
    <AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://www.example.com/assertions" index="0" isDefault="true"/>
  </SPSSODescriptor>
</EntityDescriptor>

The SP metadata also provides it’s own entityID and signing and/or encryption public keys and the NameIdFormat that it prefers to receive.

The SP shares an AssertionConsumerService endpoint that describes the endpoint where an IDP can send a response to a AuthnRequest to.

<AssertionConsumerService 
  Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
  Location="https://www.example.com/assertions"
  />

Login Flows

There are 2 ways that a login request flow can be achieved.

IDP initiated login

The first is an IDP initiated login. In this flow an IDP can send a Response message directly to the SP’s AssertionConsumerService endpoint.

Below is an example of a Response message that an IDP would send to the SP.

<?xml version="1.0"?>
<Response xmlns="urn:oasis:names:tc:SAML:2.0:protocol" ID="_8d623313-87ca-40a5-b299-694e8aaa5998" Version="2.0" IssueInstant="2019-02-23T18:10:25Z" Consent="urn:oasis:names:tc:SAML:2.0:consent:unspecified" Destination="https://www.example.com/assertions" InResponseTo="_2ff118b4-a178-46ac-82b7-374ee6314e02">
  <Issuer xmlns="urn:oasis:names:tc:SAML:2.0:assertion">https://www.example.org/metadata</Issuer>
  <Status>
    <StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
  </Status>
  <Assertion xmlns="urn:oasis:names:tc:SAML:2.0:assertion" ID="_0d856f2f-fe06-4411-8bc8-163b17142e5c" IssueInstant="2019-02-23T18:10:25Z" Version="2.0">
    <Issuer>https://www.example.org/metadata</Issuer>
    <Subject>
      <NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">22446ce2-710a-4a81-bad0-f0e3c56d1c46</NameID>
      <SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
        <SubjectConfirmationData InResponseTo="_2ff118b4-a178-46ac-82b7-374ee6314e02" Recipient="https://www.example.com/assertions" NotOnOrAfter="2019-02-23T18:15:25Z"/>
      </SubjectConfirmation>
    </Subject>
    <Conditions NotBefore="2019-02-23T18:10:25Z" NotOnOrAfter="2019-02-23T21:10:25Z">
      <AudienceRestriction>
        <Audience>https://www.example.com/metadata</Audience>
      </AudienceRestriction>
    </Conditions>
    <AuthnStatement AuthnInstant="2019-02-23T18:10:25Z" SessionIndex="_0d856f2f-fe06-4411-8bc8-163b17142e5c">
      <AuthnContext>
        <AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</AuthnContextClassRef>
      </AuthnContext>
    </AuthnStatement>
  </Assertion>
</Response>

The purpose of the Response element is to inform the SP of what happened when the user attempted to login. Ideally the StatusCode will be Success but it can also be one of many different types of error conditions.

The Assertion element describes the user that successfully logged in and how they logged in. The SP can identify which user logged in by examining the NameID element. In the example above a user with a UUID of 22446ce2-710a-4a81-bad0-f0e3c56d1c46 was able to complete authentication at the IDP.

SP initiated login

The next type of login workflow is an SP initiated login. In this flow the SP initiated the login by sending an AuthnRequest to the IDP's SingleSignOnService endpoint. The IDP will prompt the user to complete authentication (e.g. username/password challenge, MFA etc) then the IDP will send a Response message to the SP’s AssertionConsumerService endpoint.

An SP initiated login begins with an SP sending and AuthnRequest to the IDP`. Let’s examine an example.

<?xml version="1.0"?>
<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_2ff118b4-a178-46ac-82b7-374ee6314e02" Version="2.0" IssueInstant="2019-02-23T18:10:03Z" Destination="https://www.example.org/session/new" AssertionConsumerServiceURL="https://www.example.com/assertions">
  <saml:Issuer>https://www.example.com/metadata</saml:Issuer>
  <samlp:NameIDPolicy Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"/>
</samlp:AuthnRequest>

The AuthnRequest describes which entity is sending the request via the Issuer element. The NameIdPolicy describes the type of NameID the SP would like to receive from the IDP after a successful authentication at the IDP.

When the IDP receives the AuthnRequest they can begin authentication of the user and respond with a Response message back to the SP as described above in the IDP initiated login flow.

Bindings

The two common types of bindings are HTTP-Post and HTTP-redirect. The binding describes how to serialize/de-serialize the message for transport.

HTTP-Redirect Binding

The HTTP-Redirect binding compresses the message, Base64 encodes it then transports it via query string parameters in the URI. Limitations of this binding are usually related to limits in the length of the URI that a user-agent can support and request header limit configurations at destination servers.

HTTP-Post Binding

The HTTP-Post binding Base64 encodes the message it then transports it via a request body section using a POST method.

The request body is not visible in the address bar for user-agents and can usually transport larger messages.

Conclusion

This was a very brief overview of SAML 2.0. There are many parts of SAML 2.0 that I did not discuss but hopefully this provides a good overview of what SAML 2.0 is and the basic mechanics of how it works.

security