I recently introduced myself to SAML, Security Assertion Markup Language, and thought I’d pass along what I learned. These two [1 and 2] YouTube videos by PingIdentity were a helpful introduction to SAML from a high level view.
The parties involved:
- Identity Provider (IdP) – OneLogin, Salesforce, Okta, etc.
- Service Provider (SP) – TinderBox, Box, Concur, etc.
- You (Me)
To see the following steps in action, check out this great walk through with more detail about the messages.
Step 1: Unauthenticated user (You) tries to access a hosted service (SP).
Step 2: SP generates an Authentication Request (AuthnRequest)[gist https://gist.github.com/jheth/7961957]
Step 3: SP submits request to IdP (HTTP Redirect)
Step 4: IdP handles SAML Request and Authenticates User
In most cases the authentication step is done through the typical username/password login form. Since login was initiated with a SAML Request the IdP knows it must send the desired SAML Response.
Step 5: IdP generates SAML Response XML Document[gist https://gist.github.com/jheth/7962107]
Step 6: IdP submits response to SP
POST https//www.hostedservice.com/sso/saml/acs SAMLResponse: [base64 encoded XML]
Step 7: SP consumes and validates assertion
The XML document is checked for validity, which includes the conditions NotBefore and NotOnOrAfter (timestamps) and AudienceRestriction. Note: Watch out for clock-drift with the timestamp attributes, you may need to account for slight variations.
Step 8: SP grants or denies access based on the response.
Once determined to be a valid request your application is responsible for logging the user in without prompting for additional information. Once authenticated the user is redirected to the resource they originally requested.
As you can see above, there are specific URLs used by both the IdP and SP during the request/response phase. This is where configuration and an exchange of information is necessary and where some of the security of SAML comes into play.
The SP at a minimum needs to know the following, which is provided by your IdP when you register with them.
- IdP SSO Target URL: https://app.onelogin.com/trust/saml2/http-post/sso/XXXXXX
- IdP Certificate Fingerprint (SHA-1): 8D:96:A0:99:BC:11:F7:2D:70:…
- Name Identifier Format: urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress
The IdP at a minimum needs to know where to send the assertions.
- Assertion Consumer Service URL: http://www.hostedservice.com/sso/saml/acs
SAML uses public/private key combination to sign and verify requests and their response. If a fingerprint is not provided you can generate it from the x.509 certificate.
openssl x509 -noout -in cert.pem -fingerprint
Now that you understand the transaction and configuration, try adding SAML support to your Rails/Sinatra application. I chose the ruby-saml gem created by OneLogin to handle the technical details. The README has all the instructions you need to get started. ProTip: A helpful development tool for watching the request/response exchange is the SSO-Tracer plugin for Firefox.
The two routes you need are for initiating login (AuthnRequest) with the IdP (Ex./sso/saml/login) and for consuming the assertion messages (Ex. /sso/saml/acs).
User Provisioning with SAML
Not only can we authenticate existing users but we can auto-provision accounts for first-time logins. This is a great way to reduce account administration between systems. The SAML Response to the Service Provider can contain a list of user attributes (email, username, first/last name, etc) that can be used to provision a new account. In your assertion consumer method (/sso/saml/acs), if you find that the user does not exist in your system you can redirect to a new user workflow or auto-provision based on the provided attributes.