Differences Between Azure Active Directory and Red Hat SSO v7.1

Pattern / Vinoth Chandar

I recently finished implementing OAuth2 and OIDC support for Azure Active Directory in my OAuth2 + OIDC Debugger. Previously, we implemented support for Red Hat SSO v7.1 and 3Scale. This post compares the two product’s implementations of these protocols (OAuth2 and OIDC). In particular, it looks at what I had to change from a client that already supported Red Hat SSO v7.1 to make it work with Azure Active Directory (AAD). I’ll provide some commentary around why the differences exist. Some of differences are architectural philosophy; some of it is interpretation of the specs; some of it is priorities. One gets these types of differences between vendors in all software products.

The following products were used for testing.

  • Azure Active Directory v1 endpoints
  • Red Hat SSO v7.1

Disclaimer & Warning: As I have pointed out often in my blog posts, the ideal scenario is that an OAuth2 or OIDC client application is using a IdP-vendor-provided library or SDK to interact with the IdP. Ideally, that library or SDK would be officially supported by the IdP vendor. Red Hat SSO (based on Key Cloak) has client adapters for various platform. The keycloak website has additional client adapters that are not officially supported by Red Hat, but may come in handy (these are still better than interacting with the IdP via raw protocol calls). Microsoft provides a rich set of libraries called the Azure Active Directory Authentication Libraries (ADAL) for this purpose. So, most people aren’t going to have to worry about these details in most situations. If you are dealing with these details and you do not work for an Identity Provider vendor, stop and reevaluate what you are trying to accomplish.

The following differences exist:

Cloud vs On Premise: Azure Active Directory is an Identity as a Service (IDaaS) solution. Red Hat SSO runs on top of JBoss EAP and needs dedicated infrastructure resources to be deployed on. Obviously, Red Hat SSO can be deployed on Cloud Infrastructure as a Service (IaaS). Wherever it is deployed, it must be installed— this doesn’t have to be done with the IDaaS solution. Though, both products need to have the identity configuration applied (ie, the AAD tenant must be configured and the Red Hat SSO realm must be configured).

Token Endpoint supports CORS in Red Hat SSO; AAD does not support for CORS: Without Cross-Origin Resource Sharing (CORS) support Javascript (running in the browser) loaded from a third-party site (like the debugger) cannot read the responses from the AAD Token Endpoint. This is part of the Microsoft security design. Microsoft does not want developers/applications using the Token Endpoint with SPA (or Javascript) applications (running in a browser). This corresponds to the desire to have SPAs using the OAuth2 Implicit Grant or OIDC Implicit Flow generally. The specs allow exceptions to this that I discuss elsewhere.

This required redesigning the debugger to have a backend that handled interaction with the Token Endpoint from a non-browser component (i.e., something that doesn’t have the limitations associated with CORS).

Self-Signed Certs vs Public-CA-Issued Certs: The Red Hat SSO instance I was using for testing the original development of the debugger used a self-signed certificate. Since all interaction with the IdP was between the browser and IdP endpoints, the user simply had to accept the self-signed certificate when prompted by the browser. If the IdP uses a certificate issued by a public Certificate Authority (CA), then the browser will trust it based upon its truststore. Per the last point (CORS support), the debugger backend must now interact with the token endpoint for AAD. To handle self-signed certificates, an option to disable SSL/TLS certificate trust chain validation in the Ruby/Sinatra runtime has been added to the token endpoint section of the debugger.

Refresh Token Format: Red Hat SSO uses JWT for the refresh token; AAD uses an opaque token (ie, not JWT). The exact nature of AAD’s refresh token implementation wasn’t explored beyond confirming it wasn’t JWT and it is not base64 encoded (or if it is, then it is binary and opaque). Opaque means that it is likely randomly generated or if it does have a deeper meaning it is proprietary and not immediately recognizable). Note, base64decode.org was used to test decoding the AAD refresh token.

Client Credential Grant Refresh Token: The OAuth2 Client Credential Grant implementation in Red Hat SSO returns a refresh token for a successful client authentication. AAD does not include a Refresh Token. The OAuth2 spec states:

4.4.3. Access Token Response
If the access token request is valid and authorized, the authorization server issues an access token as described in
Section 5.1.  A refresh token SHOULD NOT be included.  If the request failed client authentication or is invalid, the authorization server returns an error response as described in Section 5.2.

AAD follows the RFC recommendation of not including a refresh token for the client credential grant. Red Hat (or the Keycloak project) saw fit to include one. The RFC recommends that a refresh token not be returned in this situation presumably because it doesn’t involve an end user authentication and is acting on its own behalf. Furthermore, the client always has access to the the client identifier and client secret. It can easily use those credentials to obtain a new access token rather than dealing with the complexities of caching refresh tokens.

JWT fields (ID Token):

Both AAD & Red Hat SSO use JSON Web Tokens (JWT) as required by the OIDC spec. However, the contents of the ID Token are different between the two.

AAD:

{
  "aud": "2b58e2a5-6034-4c57-859c-b85c0507f9ed",
  "iss": "https://sts.windows.net/tenant-id-goes-here/",
  "iat": 1513090720,
  "nbf": 1513090720,
  "exp": 1513094620,
  "aio": "blahblah==",
  "amr": [
    "pwd"
  ],
  "email": "user1@test.com",
  "family_name": "535bfceb-1185-4163-84f0-65c1a6a2fea8",
  "given_name": "user1@test.com",
  "idp": "live.com",
  "ipaddr": "1.1.1.1",
  "name": "User1@test.com 535bfceb-1185-4163-84f0-65c1a6a2fea8",
  "nonce": "e546896f-7e25-4a76-9c1a-cfba93925ce2",
  "oid": "fb2b0084-e4fb-4716-9d1a-002baf2a2220",
  "sub": "F2HUnrpqxpSnMp8cHJg4t6bVrTnvOV2pKdDClfEEaEM",
  "tid": "b897f4ff-b252-4e1d-9f40-92dd80160fdc",
  "unique_name": "live.com#User1@test.com",
  "uti": "jgQygIUMX02Co4n_A_Q1AA",
  "ver": "1.0"
}

Red Hat SSO:

{
  "jti": "c87e139d-b80c-438f-a035-e41ce85e4fd2",
  "exp": 1513095172,
  "nbf": 0,
  "iat": 1513091572,
  "iss": "https://idp.levvel.io/auth/realms/blog_demo",
  "aud": "blog-post-demo-client-001",
  "sub": "71c904f1-e978-4542-80de-fa98ebb241e5",
  "typ": "ID",
  "azp": "blog-post-demo-client-001",
  "nonce": "b69b28d2-1176-4a5a-a047-0405963c3c7a",
  "auth_time": 1513091518,
  "session_state": "15b561a2-f539-4685-bba1-fa2a759d1cb1",
  "acr": "1",
  "name": "",
  "preferred_username": "user1"
}

Claims:

  • Present in both tokens: aud, iss, exp, nbf, iat, amr, nonce, sub, name. Most of these are defined in the OIDC spec or OAuth2 RFC. The “name” field is not defined in either of these specs. A description of these fields can be found here.
  • Present in AAD tokens; absent from Red Hat SSO tokens: aio, email, family_name, given_name, idp, ipaddr, oid, tid, unique_name, uti, ver. These fields are analzyed here.
  • Present in Red Hat SSO tokens; absent from AAD tokens: jti, typ, azp, auth_time, session_state, acr, preferred_username.

AAD requires resource parameter for the OAuth2 Implicit Grant; Red Hat SSO does not: Azure Active Directory requires a resource parameter to be included in the request to the Authorization Endpoint. The resource parameter value will typically be the client identifier, but could also be a delegated resource. Neither the OAuth2 nor OIDC specs define the resource parameter. The OAuth2 Token Exchange RFC does describe the use of the resource parameter for token exchange calls. This spec isn’t directly involved in the types of calls that the OAuth2 + OIDC Debugger currently supports.

Supported OIDC Flows: Azure Active Directory (v1 endpoints) supports:

  • Full OAuth2 implementation
  • OIDC Authorization Code Flow
  • OIDC Implicit Flow (both variants)
  • OIDC Hybrid Flow with response_type=”code id_token”

AAD does not support the other two OIDC Hybrid Flow (response_type=”code token” and response_type=”code id_token token”).

Red Hat SSO is a full implementation of OpenID Connect v1.0. As noted in earlier blog posts, the Hybrid Flow isn’t used that much, which is probably why Microsoft only implemented one of the three variants of it.

Summary

The differences laid out here guided the updates I made to the OAuth2 + OIDC Debugger to support Azure Active Directory. This also provides a good example of differences that can arise between vendors for implementations of the OAuth2 and OpenID Connect specifications.

Image: Pattern / Vinoth Chandar