Security Assertion Markup Language (SAML) is an open standard that allows identity providers (IdP) to pass authorization credentials to service providers (SP). What that jargon means is that you can use one set of credentials to log into many different websites. It’s much simpler to manage one login per user than it is to manage separate logins to email, customer relationship management (CRM) software, Active Directory, etc.
SAML transactions use Extensible Markup Language (XML) for standardized communications between the identity provider and service providers. SAML is the link between the authentication of a user’s identity and the authorization to use a service. (From here)
SAML vs. OAuth
OAuth is a slightly newer standard that was co-developed by Google and Twitter to enable streamlined internet logins. OAuth uses a similar methodology as SAML to share login information. SAML provides more control to enterprises to keep their SSO logins more secure, whereas OAuth is better on mobile and uses JSON.
Schema
Step 1 - We try to access some protected resource
Step 2 - The server where that resource resides (Service Provider) doesn’t know us, so it generates a SAML Request to be sent to the Identity Provider. This would be like showing up to Germany without our passport and getting sent back to the US to get our passport before being able to get into the country.
Step 3 - After generating the SAML Request, the SP redirects us to the IdP. Note: The SAML Request passes through our browser on the way to the IdP.
Step 4 - The IdP receives the SAML Request
Step 4a (not pictured) - The IdP provides some means of authentication; a login form or something similar.
Step 4b (not pictured) - The IdP validates us as a legitimate user that should be allowed to access the resource included as part of the SAML Request
Step 5 - The IdP creates a SAML Response. The SAML Response contains the SAML Assertions necessary for the SP. The Assertion usually includes the following information at a minimum: Indication that the Assertion is from the correct IdP, a NameID attribute specifying who the user is, and a digital signature. The SAML Response also passes through our browser.
Step 6 - The IdP redirects us to the SP’s Assertion Consumer Service (ACS) URL. The ACS is simply the URL on which the SP expects to receive SAML assertions.
Step 7 - The ACS validates the SAML Response.
Step 8 - We are allowed to access the resource we originally requested.
SAML Request Example
Let’s take a closer look at steps 2 and 3 outlined above. We’ll make a request to the example Service Provider for the resource located at https://shibdemo-sp1.test.edu/secure/, which as its name implies, is content that requires us to be authenticated to view.
shibdemo-sp1.test.edu is a local virtualized instance of an IdP and SP for testing, not an actual site
GET /secure/ HTTP/1.1
Host: shibdemo-sp1.test.edu
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:65.0) Gecko/20100101 Firefox/65.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: https://shibdemo-sp1.test.edu/
Connection: close
Upgrade-Insecure-Requests: 1
The SP generates a SAML Request because we’re not authenticated. We can see the raw SAML Request below.
AssertionConsumerServiceURL: Identifies where the IdP should send the SAML Response to after authentication
Destination: Indicates the address to which the request should be sent (IdP)
ProtocolBinding: Typically accompanies the AssertionConsumerServiceURL attribute; defines the mechanism by which SAML protocol messages will be transmitted
saml:Issuer: Identifies the entity that generated the request message
We’ve outlined the more pertinent elements of the request above, but details about any of the other elements can be viewed in the core specification. The request above goes something like this: “Hey, please authenticate the user that sent this message to you and then have that same user hit me up when you two are done”.
With the SAML Request created, the SP now replies to our GET request for /secure/ with a 302 redirect. The 302 directs our browser to head over to the IdP. The SAML Request is encoded into the HTTP response’s Location header as part of the 302.
HTTP/1.1 302 Found
Date: Tue, 12 Mar 2019 20:54:58 GMT
Server: Apache/2.2.3 (CentOS)
Expires: Wed, 01 Jan 1997 12:00:00 GMT
Cache-Control: private,no-store,no-cache,max-age=0
Location: https://shibdemo-idp.test.edu/idp/profile/SAML2/Redirect/SSO?SAMLRequest=fZJdT4MwFIb%2FCuk9FNgmWzNIcLtwyXRkoBfemFKO0gRa7Cl%2B%2FHvZmDoTs8u2b5%2B350mXyNumY2lva7WH1x7QOh9to5AdD2LSG8U0R4lM8RaQWcHy9HbLQs9nndFWC90QJ0UEY6VWK62wb8HkYN6kgPv9Nia1tR0ySrGWZQWtdrELPDs0eVD1NB92S92ArT1ETQ%2FwkGa7vCDOeshIxQ%2Fcfyiy6n4pw4IOz3mWDZwQe6ikAWFpnu%2BIs1nH5ElUHKJgHk7mJV%2BI0I%2F4ZCZEJCK%2F9KdX3B9iiD1sFFqubExCP1i4%2FsQNwiL02WzKZvNH4mSnqa%2BlqqR6uayoHEPIbooic8exHsDgcaQhQJLlQTQ7Fpsz9Zex%2FNs3SS7bxR%2B7S3pWNLZ27G4gb9aZbqT4dNKm0e8rA9xCTAJCk%2FHK39%2BRfAE%3D&RelayState=ss%3Amem%3A39430bdac29d44586c326f12b4cb3345ffa47137a374e37cba0877e0fc79ea91
Content-Length: 897
Connection: close
Content-Type: text/html; charset=iso-8859-1
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>302 Found</title>
</head><body>
<h1>Found</h1>
<p>The document has moved <a href="https://shibdemo-idp.test.edu/idp/profile/SAML2/Redirect/SSO?SAMLRequest=fZJdT4MwFIb%2FCuk9FNgmWzNIcLtwyXRkoBfemFKO0gRa7Cl%2B%2FHvZmDoTs8u2b5%2B350mXyNumY2lva7WH1x7QOh9to5AdD2LSG8U0R4lM8RaQWcHy9HbLQs9nndFWC90QJ0UEY6VWK62wb8HkYN6kgPv9Nia1tR0ySrGWZQWtdrELPDs0eVD1NB92S92ArT1ETQ%2FwkGa7vCDOeshIxQ%2Fcfyiy6n4pw4IOz3mWDZwQe6ikAWFpnu%2BIs1nH5ElUHKJgHk7mJV%2BI0I%2F4ZCZEJCK%2F9KdX3B9iiD1sFFqubExCP1i4%2FsQNwiL02WzKZvNH4mSnqa%2BlqqR6uayoHEPIbooic8exHsDgcaQhQJLlQTQ7Fpsz9Zex%2FNs3SS7bxR%2B7S3pWNLZ27G4gb9aZbqT4dNKm0e8rA9xCTAJCk%2FHK39%2BRfAE%3D&RelayState=ss%3Amem%3A39430bdac29d44586c326f12b4cb3345ffa47137a374e37cba0877e0fc79ea91">here</a>.</p>
<hr>
<address>Apache/2.2.3 (CentOS) Server at shibdemo-sp1.test.edu Port 443</address>
</body></html>
The RelayState parameter sent along with the SAML Request is state information sent by the SP to the IdP so that the SP knows who initially asked for the resource when the SAML Response comes back. The SAML Response must contain the same RelayState value.
The SAMLRequest parameter is a compressed and encoded version of the same raw xml snippet we looked at earlier. SAML uses the Deflate compression algorithm then base64 encodes the result.
SAML Response Example
We’re going to eschew stepping through the part where the user authenticates to the IdP and jump straight into steps 5 and 6 from what was discussed in the SAML Authentication Workflow. Just keep in mind that what we’re going to look at happens after the user authenticates to the IdP.
Let’s start by taking a look at the raw SAML Response.
ds:Signature: An XML Signature that protects the integrity of and authenticates the issuer of the assertion; the SAML assertion MAY be signed but doesn’t have to be. The example above contains two ds:Signature elements. The reason is that one is the message’s signature; the other is the Assertion’s signature.
saml:Assertion: Contains information about the user’s identity and potentially other user attributes.
saml:Subject: Specifies the principal that is the subject of all of the statements in the assertion.
saml:StatusCode: A code representing the status of the activity carried out in response to the corresponding request.
saml:Conditions: Specifies things like the time an Assertion is valid and that the Assertion is addressed to a particular Service Provider.
saml:AuthnStatement: States that the IdP authenticated the Subject of the Assertion.
saml:AttributeStatement: Contains Attributes that describe the Subject of the Assertion.
Here’s a more straightforward visual representation of the same SAML Response.
Now that we’ve authenticated with the IdP and it has generated the SAML Response above, it responds to our authentication with another 302 redirect.
The 302 ultimately leads to us making a POST request to the Service Provider’s Assertion Consumer Service URL. The POST body contains the RelayState and SAMLResponse parameters. Recall that the ACS processes and validates the SAML Response.
Once the POST request is received, and the SAML Response is validated, we can access the protected resource we initially requested.
GET /secure/ HTTP/1.1
Host: shibdemo-sp1.test.edu
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:65.0) Gecko/20100101 Firefox/65.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: https://shibdemo-idp.test.edu/idp/profile/SAML2/Redirect/SSO
Connection: close
Cookie: _shibsession_64656661756c7468747470733a2f2f7368696264656d6f2d7370312e746573742e6564752f73686962626f6c657468=_ac05716a62d3ee9450c863b093f32bbb
Upgrade-Insecure-Requests: 1
HTTP/1.1 200 OK
Date: Tue, 12 Mar 2019 20:55:04 GMT
Server: Apache/2.2.3 (CentOS)
X-Powered-By: PHP/5.1.6
Content-Length: 1047
Connection: close
Content-Type: text/html; charset=UTF-8
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>IDM Integration</title>
-------------8<-------------
XML Signatures
We’re almost done covering all the basics we need to cover in order to move on to the actual testing! The last item we need to cover is XML Signatures. Interestingly, XML Signatures can be used to sign either a whole XML tree or specific elements within the tree. We already saw earlier that two separate XML Signatures were used in our example SAML Response. Each signature was responsible for a different part of the Response. In this section, we’ll look at the different ways an XML Signature can be incorporated into an XML document. Something to note is that while our examples use the Response element as the resource to be signed, XML Signatures can be applied to any Object, including Assertion elements.
ENVELOPED SIGNATURE
A basic XML Signature is comprised of the following elements.
Of particular note for us is that each resource to be signed has its own Reference element. The Reference element’s URI attribute denotes which resource is signed by that particular Signature. By examining our example from earlier, we can see this in practice.
What we saw in our example earlier is known as an enveloped signature. An enveloped signature is a signature that is a descendant of the resource it’s signing. We can see that spelled out for us in the ds:Transform element of our example.
Finally, there are detached signatures. A detached signature is neither wrapping nor is it wrapped by the resource to be signed. Instead, it is wholly separate from the signed resource.