Link Search Menu Expand Document

Commander™ Security

Jan 1 2022 at 12:00 AM

  1. Commander™ Authentication
  2. Authentication
  3. API Access
  4. OpenID Connect and OAuth 2.0
  5. Terminology
  6. Identity Server
  7. User
  8. Client
  9. Resources
  10. Identity Token
  11. Access Token
  12. Built to Specification
    1. OpenID Connect
    2. OAuth 2.0
  13. Grant Types
    1. Machine to Machine Communication
    2. Interactive Clients
    3. Interactive clients without browsers or with constrained input devices
  14. Secrets
  15. Refresh Tokens
  16. Reference Tokens
  17. Authorise Request Objects
  18. CORS
    1. Client-based CORS Configuration
  19. Endpoints
    1. Discovery Endpoint
    2. Authorise Endpoint

This section provides an overview of the Commander™ platform security.

Commander™ Authentication

Most modern applications look like this:

Most modern applications

Figure 1 - Most modern applications

The most common interactions are:

  • Browsers communicate with web applications

  • Web applications communicate with web APIs (sometimes on their own, sometimes on behalf of a user)

  • Browser-based applications communicate with web APIs

  • Native applications communicate with web APIs

  • Server-based applications communicate with web APIs

  • Web APIs communicate with web APIs (sometimes on their own, sometimes on behalf of a user)

Typically, every layer (front-end, middle-tier and back-end) must protect resources and implement authentication and/or authorisation – often against the same user store. Outsourcing these fundamental security functions to a security token service prevents duplicating that functionality across those applications and endpoints. Restructuring the application to support a security token service leads to the following architecture and protocols:

Customer Cloud / Server

Figure 2 - Customer Cloud / Server

Authentication

Authentication is needed when an application needs to know the identity of the current user. Typically, these applications manage data on behalf of that user and need to make sure that this user can only access the data for which he is allowed. The most common example for that is (classic) web applications – but native and JS-based applications also have a need for authentication. The most common authentication protocols are SAML2p, WS-Federation and OpenID Connect – SAML2p being the most popular and the most widely deployed. OpenID Connect is the newest of the three but is likely to see the most usage in the future because it has the most potential for modern applications. It was built for mobile application scenarios right from the start and is designed to be API friendly.

API Access

Applications have two fundamental ways with which they communicate with APIs – using the application identity or delegating the user’s identity. Sometimes both methods need to be combined. OAuth2 is a protocol that allows applications to request access tokens from a security token service and use them to communicate with APIs. This delegation reduces complexity in both the client applications as well as the APIs since authentication and authorisation can be centralised.

OpenID Connect and OAuth 2.0

OpenID Connect and OAuth 2.0 are very similar – in fact, OpenID Connect is an extension on top of OAuth 2.0. The two fundamental security concerns, authentication, and API access are combined into a single protocol - often with a single round trip to the security token service. We believe that the combination of OpenID Connect and OAuth 2.0 is the best approach to secure modern applications for the foreseeable future. IdentityServer4 is an implementation of these two protocols and is highly optimized to solve the typical security problems of today’s mobile, native and web applications.

Terminology

Identity Server

Figure 3 - Identity Server

Identity Server

Identity Server is an OpenID Connect provider - it implements the OpenID Connect and OAuth 2.0 protocols. Different literature uses different terms for the same role but you will probably also find security token service, identity provider, authorisation server, IP-STS and more.

User

A user is a human that is using a registered client to access resources.

Client

A client is a piece of software that requests tokens from Identity Server - either for authenticating a user (requesting an identity token) or for accessing a resource (requesting an access token). A client must be first registered with Identity Server before it can request tokens. Examples for clients are web applications, native mobile or desktop applications, SPAs, server processes etc.

Resources

Resources are something you want to protect with Identity Server - either identity data of your users, or APIs. Every resource has a unique name, and clients use this name to specify to which resources they want to get access to. Identity data may include identity information (aka claims) about a user, e.g. name or email address. API resources represent functionality a client wants to invoke and is typically modelled as Web APIs, but not necessarily.

Identity Token

An identity token represents the outcome of an authentication process. It contains at a bare minimum an identifier for the user (called the sub aka subject claim) and information about how and when the user authenticated. It can also contain additional identity data.

Access Token

An access token allows access to an API resource. Clients request access tokens and forward them to the API. Access tokens contain information about the client and the user (if present). APIs use that information to authorize access to their data.

Built to Specification

OpenID Connect

  • OpenID Connect Core 1.0 (spec)

  • OpenID Connect Discovery 1.0 (spec)

  • OpenID Connect Session Management 1.0 - draft 28 (spec)

  • OpenID Connect Front-Channel Logout 1.0 - draft 02 (spec)

  • OpenID Connect Back-Channel Logout 1.0 - draft 04 (spec)

OAuth 2.0

Grant Types

The OpenID Connect and OAuth 2.0 specifications define so-called grant types (often also called flows - or protocol flows). Grant types specify how a client can interact with the token service. This allows locking down the protocol interactions that are allowed for a given client. A client can be configured to use more than a single grant type (e.g. Authorisation Code flow for user centric operations and client credentials for server to server communication).

Machine to Machine Communication

This is the simplest type of communication. Tokens are always requested on behalf of a client; no interactive user is present. In this scenario, you send a token request to the token endpoint using the client credentials grant type. The client typically must authenticate with the token endpoint using its client ID and secret.

Interactive Clients

This is the most common type of client scenario: web applications, SPAs or native/mobile apps with interactive users. For this type of clients, the authorisation code flow was designed. That flow consists of two physical operations:

  • a front-channel step via the browser where all “interactive” things happen, e.g. login page, consent etc. This step results in an authorisation code that represents the outcome of the front-channel operation.

  • a back-channel step where the authorisation code from step 1 gets exchanged with the requested tokens. Confidential clients need to authenticate at this point.

This flow has the following security properties:

  • no data (besides the authorisation code which is basically a random string) gets leaked over the browser channel

  • authorisation codes can only be used once

  • the authorisation code can only be turned into tokens when (for confidential clients but more on that later) the client secret is known

This all sounds very good, still, there is one problem called a code substitution attack. There are two modern mitigation techniques for this:

OpenID Connect Hybrid Flow

This uses a response type of code id_token to add an additional identity token to the response. This token is signed and protected against substitution. In addition, it contains the hash of the code via the c_hash claim. This allows checking that you indeed got the right code (experts call this a detached signature). This solves the problem but has the following down sides:

  • the id_token gets transmitted over the front-channel and might leak additional (personal identifiable) data.

  • all the mitigation steps (e.g. crypto) need to be implemented by the client. This results in more complicated client library implementations.

RFC 7636 - Proof Key for Code Exchange (PKCE)

This essentially introduces a per-request secret for code flow (please read up on the details here). All the clients must implement this by creating a random string and hashing it using SHA256. This also solves the substitution problem, because the client can prove that it is the same client on front and back-channel, and has the following additional advantages:

  • the client implementation is very simple compared to hybrid flow

  • it also solves the problem of the absence of a static secret for public clients

  • no additional front-channel response artefacts are needed

Summary

Interactive clients should use an authorisation code-based flow. To protect against code substitution, either hybrid flow or PKCE should be used. If PKCE is available, this is the simpler solution to the problem. PKCE is already the official recommendation for native applications and SPAs - and with the release of ASP.NET Core 3 also by default supported in the OpenID Connect handler as well.

Interactive clients without browsers or with constrained input devices

This grant type is detailed RFC 8628.

This flow outsources user authentication and consent to an external device (e.g. a smart phone). It is typically used by devices that don’t have proper keyboards (e.g. TVs, gaming consoles, etc ) and can request both identity and API resources.

Secrets

In certain situations, clients need to authenticate with identity server, for example:

  • confidential applications (aka clients) requesting tokens at the token endpoint.

  • APIs validating reference tokens at the introspection endpoint.

For that purpose, you can assign a list of secrets to a client or an API resource. Secret parsing and validation is an extensibility point in identity server, out of the box it supports shared secrets as well as transmitting the shared secret via a basic authentication header or the POST body.

Refresh Tokens

Since access tokens have finite lifetimes, refresh tokens allow requesting new access tokens without user interaction. Refresh tokens are supported for the following flows: authorisation code, hybrid, and resource owner password credential flow. The clients need to be explicitly authorized to request refresh tokens by setting AllowOfflineAccess to true.

AbsoluteRefreshTokenLifetime: Maximum lifetime of a refresh token in seconds. Defaults to 2592000 seconds / 30 days. Zero allows refresh tokens that, when used with RefreshTokenExpiration = Sliding only expire after the SlidingRefreshTokenLifetime is passed.

SlidingRefreshTokenLifetime: Sliding lifetime of a refresh token in seconds. Defaults to 1296000 seconds / 15 days.

RefreshTokenUsage:

  • ReUse the refresh token handle will stay the same when refreshing tokens.

  • OneTime the refresh token handle will be updated when refreshing tokens.

RefreshTokenExpiration

  • Absolute the refresh token will expire on a fixed point in time (specified by the AbsoluteRefreshTokenLifetime).

  • Sliding when refreshing the token, the lifetime of the refresh token will be renewed (by the amount specified in SlidingRefreshTokenLifetime). The lifetime will not exceed AbsoluteRefreshTokenLifetime.

UpdateAccessTokenClaimsOnRefresh Gets or sets a value indicating whether the access token (and its claims) should be updated on a refresh token request

Reference Tokens

Access tokens can come in two flavours - self-contained or reference. A JWT token would be a self-contained access token - it is a protected data structure with claims and an expiration. Once an API has learned about the key material, it can validate self-contained tokens without needing to communicate with the issuer. This makes JWTs hard to revoke. The JWT tokens will stay valid until they expire. When using reference tokens – Identity Server will store the contents of the token in a data store and will only issue a unique identifier for this token back to the client. The API receiving this reference must then open a back-channel communication to Identity Server to validate the token. This introduces additional network traffic and latency.

Reference Token

Figure 4 - Reference Token

Authorise Request Objects

Instead of providing all parameters for an authorise request as individual query string parameters, you can package them up in signed JWTs. You can either transmit them by value or by reference to the authorise endpoint - see the spec for more details. Identity Server requires the request JWTs to be signed. We support X509 certificates, symmetric and RSA keys. Authorisation is always done by Roles and Permissions to determine if access to a resource is permitted.

CORS

Many endpoints in Identity Server will be accessed via Ajax calls from JavaScript-based clients. Given that Identity Server will most likely be hosted on a different origin than these clients, this implies that Cross-Origin Resource Sharing (CORS) will need to be configured.

Client-based CORS Configuration

One approach to configuring CORS is to use the AllowedCorsOrigins collection on the client configuration. Simply add the origin of the client to the collection and the default configuration in Identity Server will consult these values to allow cross-origin calls from the origins.

——————————————————————————————————–

Note: Be sure to use an origin (not a URL) when configuring CORS. For example: https://foo:123/ is a URL, whereas https://foo:123 is an origin.

——————————————————————————————————–

Endpoints

Discovery Endpoint

The discovery endpoint can be used to retrieve metadata about your Identity Server - it returns information like the issuer name, key material, supported scopes etc. See the spec for more details. The discovery endpoint is available via /.well-known/openid-configuration relative to the base address, e.g.: https://{commander-domain}/auh/.well-known/openid-configuration

Authorise Endpoint

The authorise endpoint can be used to request tokens or authorisation codes via the browser. This process typically involves authentication of the end-user and optionally consent.

  • client_id identifier of the client (required)

  • request instead of providing all parameters as individual query string parameters, you can provide a subset or all of them as a JWT

  • request_uri URL of a pre-packaged JWT containing request parameters

  • scope one or more registered scopes (required)

  • redirect_uri must exactly match one of the allowed redirect URIs for that client (required)

  • response_type id_token requests an identity token (only identity scopes are allowed)

  • token requests an access token (only resource scopes are allowed)

  • id_token token requests an identity token and an access token

  • code requests an authorization code

  • code id_token requests an authorisation code and identity token

  • code id_token token requests an authorisation code, identity token and access token

  • response_mode form_post sends the token response as a form post instead of a fragment encoded redirect (optional)

  • state identity server will echo back the state value on the token response, this is for round tripping state between client and provider, correlating request and response and CSRF/replay protection. (recommended)

  • nonce identity server will echo back the nonce value in the identity token, this is for replay protection) Required for identity tokens via implicit grant.

  • prompt none no UI will be shown during the request. If this is not possible (e.g. because the user must sign in or consent) an error is returned login the login UI will be shown, even if the user is already signed-in and has a valid session

  • code_challenge sends the code challenge for PKCE

  • code_challenge_method plain indicates that the challenge is using plain text (not recommended) S256 indicates the challenge is hashed with SHA256

  • login_hint can be used to pre-fill the username field on the login page

  • ui_locales gives a hint about the desired display language of the login UI

  • max_age if the user’s logon session exceeds the max age (in seconds), the login UI will be shown

  • acr_values allows passing in additional authentication related information – identity server special cases the following proprietary acr_values: idp:name_of_idp bypasses the login/home realm screen and forwards the user directly to the selected identity provider (if allowed per client configuration) tenant:name_of_tenant can be used to pass a tenant name to the login UI