Implementation Expectations

Looking for a more detailed, technical breakdown of how Skuid works with SAML bearer assertion authentication and OAuth2.0? Read below.

Background

The OAuth 2.0 specification provides various “grant types” by which a user can obtain an Access Token to present to data source APIs as a means of authentication. The most commonly-used grant type is “Authorization Code”, which requires users to first authorize a given OAuth client by going to an authorization server’s “Authorization URL”. Here they are asked to login to the authorizing party (if they have not already done so) and then, if the user has not already done so, authorize the Client to grant access to resources. Once authorization is complete, the authorization server issues an “authorization code”, which the user can then exchange for an “access token”. This access token can then be presented to a given data source’s APIs as a Bearer token (i.e. in a header named “authorization” with value “Bearer <access_token>”) to authenticate the user.

In an enterprise environment, this requirement for individual users to authorize a given Client is not ideal. Enterprises expect a “Single Sign On” experience where an Administrator “pre-approves” users to access various applications. This is typically implemented using a federated authentication protocol such as SAML 2.0. However, SAML 2.0 is typically only used for allowing users to log-in to a web application’s user interface. After a user logs in to their company’s Identity Provider (IdP), the IdP typically presents them with a screen containing a list of service providers—applications which they are approved to access. The user can then click on a given service provider (SP), and the IdP will initiate single-sign on into the SP, and the user’s browser will be dropped at the SP’s “Start URL”—a designated starting page for entry into the SP’s application.

OAuth 2.0 defines an extension grant type, known as “OAuth-SAML Bearer Assertion”, which bridges the gap between OAuth 2.0 and SAML 2.0, allowing for a Single Sign On experience to not just web applications, but also web APIs. The assumption is that an enterprise has an existing federated identity structure implemented using SAML 2.0, and has various data source APIs that require authentication. This grant type allows for enterprises to securely “pre-authorize” users to access data source APIs. A given data source must be configured as a SAML service provider, and an OAuth client must be registered that is linked to this SAML service provider. A user can then submit a SAML IdP to the data source’s OAuth Access Token URL. The OAuth Access Token URL must then read the SAML IdP, and use it to identify the user that is requesting access. If the user is unknown, or has not been pre-authorized to use this OAuth client, the access token request is denied.

If the user is known, and has been pre-authorized to use this OAuth client, then a check is made to see if the user has an established Session created via SAML. If such Session exists, then the user is granted an access token. If not, then a SAML AuthnRequest should be sent to the IdP to authenticate the user (SP-Initiated SSO). If this AuthnRequest succeeds, then a Session should be created in the SP, and the user should be granted an access token.

Implementation Details

Skuid can be configured to access a data source using the OAuth-SAML Bearer Assertion grant type. Once an access token has been obtained, Skuid will store the access token and use it to access the data source until the token expires / fails, at which point Skuid will attempt to acquire a new access token by re-authenticating.

When authenticating to a data source using the OAuth-SAML Bearer Assertion grant type, Skuid creates a SAML IdP (server-side, using Skuid’s embedded proxy) and sends this assertion in the body of a request to the data source’s configured Access Token Request URL as per the specification, for example, an assertion such as the following will be sent:

<Assertion IssueInstant="2010-10-01T20:07:34.619Z"
   ID="ef1xsbZxPV2oqjd7HTLRLIBlBb7"
   Version="2.0"
   xmlns="urn:oasis:names:tc:SAML:2.0:assertion">
  <Issuer>https://saml-idp.example.com</Issuer>
  <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
   [...omitted for brevity...]
  </ds:Signature>
  <Subject>
   <NameID
   Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">
   brian@example.com
   </NameID>
   <SubjectConfirmation
    Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
   <SubjectConfirmationData
    NotOnOrAfter="2010-10-01T20:12:34.619Z"
    Recipient="https://authz.example.net/token.oauth2"/>
   </SubjectConfirmation>
   </Subject>
   <Conditions>
    <AudienceRestriction>
     <Audience>https://saml-sp.example.net</Audience>
    </AudienceRestriction>
   </Conditions>
   <AuthnStatement AuthnInstant="2010-10-01T20:07:34.371Z">
    <AuthnContext>
     <AuthnContextClassRef>
      urn:oasis:names:tc:SAML:2.0:ac:classes:X509
     </AuthnContextClassRef>
    </AuthnContext>
   </AuthnStatement>
  </Assertion>

All recommendations of the spec should be enforced, e.g. the SubjectConfirmationData and IssueInstant should be used to invalidate old / expired IdPs, the Signature should be validated, etc.

Here is a summary of some key values that Skuid will inject into the assertion, which are crucial for an implementation to succeed.

  • Issuer: The Client Id configured in the Skuid data source.
  • Audience: The Access Token Endpoint URL configured in the data source
  • Recipient: The Access Token Endpoint URL configured in the data source
  • NameID: This is configurable, can be the Skuid user’s username, Federation Identifier, Email Address, or a formula-derived combination of user fields, e.g. a combination of the First Name and Last Name, with some separator characters.

The assertion will be base64url encoded.

Note: This is not the same as URL-encoding and then Base64 encoding; it is a unique standard. Please see the link to see how the alphabet differs from regular Base64 (two characters are different), and placed in the request body along with a grant_type parameter, e.g.

1
2
3
4
5
6
POST /token.oauth2 HTTP/1.1
Host: authz.example.net
Content-Type: application/x-www-form-urlencoded
grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Asaml2-
bearer&assertion=PEFzc2VydGlvbiBJc3N1ZUluc3RhbnQ9IjIwMTEtMDU
[...omitted for brevity...]aG5TdGF0ZW1lbnQ-PC9Bc3NlcnRpb24-