Using the Dynamic Authenticator

Using the Dynamic Authenticator

In the Curity Identity Server authenticators represent the methods that are used to assert information about a user logging in to the system. They can be chained together and accompanied by Actions to form complex authentication flows. Normally, all the configuration required by an authenticator to do its job is contained in the Curity Identity Server and managed through the admin UI, configuration CLI or the RESTConf API. However, there are setups where the Curity Identity Server is federated with numerous external providers to perform authentication. When the number of such federations grow, it might become cumbersome to manage all the settings directly in the Curity Identity Server. If the federation involves dozens or even a couple-hundred of providers, then it is simpler to use a Dynamic Authenticator instead of configuring every integration separately.

The Dynamic Authenticator

The Dynamic Authenticator is an authenticator that is capable of reading configuration from a remote source and to delegate the actual authentication to another authenticator (using the configuration read from the remote). Have a look at the diagram below.

Dynamic Authenticator overview

The authenticator is first fed information that is used to determine the concrete federation (i.e. authenticator) that should be used in the current authentication flow. For example, use the domain of the user’s email address to resolve the federation id. Add this data to the context attribute dynamic-authenticator-federation-id. This is the attribute the Dynamic Authenticator reads and uses to load the configuration for the delegated authenticator. The authenticator then calls the external source to get the configuration for the instance of the authenticator it should delegate to. The external source is called with the value of the federation ID attribute and the type of the authenticator. The Dynamic Authenticator itself is configured with the type of the delegate authenticator. It knows upfront that it will be delegating authentication to instances of e.g., an OIDC authenticator. The instance of the Dynamic Authenticator will always delegate to the given type of authenticator.

Supported authenticators and data sources

Have a look at the Dynamic Authenticator's documentation to check which authenticators and data sources are currently supported by the Dynamic Authenticator.

The external source will respond with a JSON representation of the configuration required by the authenticator that the Dynamic Authenticator delegates to. For example, for the oidc type of delegation the external source will return fields like configuration-url, client-id, http-client, etc.

To learn what fields should be returned by the external service have a look at an instance of the delegate authenticator. For example, for the oidc authenticator check the authenticator's documentation or create the authenticator in the admin UI to see what options are supported, then view the configuration's XML to see the names of the configuration fields.

Once the Dynamic Authenticator gets the configuration, the Curity Identity Server (technically the current runtime node) caches it and creates an instance of the described authenticator that it delegates the authentication to. After the delegate authenticator finishes authentication, the Dynamic Authenticator resumes the authentication flow with any actions.

Externally provided configuration is not statically verified

The configuration that comes from the external provider is not statically verified. This means that you must take care to properly set any references in that external configuration. E.g., if the external configuration returns an identifier of an HTTP client, you must make sure that the given client exists in the system. Otherwise, runtime errors will occur and users will not be able to authenticate using the misconfigured provider.

The OIDC Authenticator

The Dynamic Authenticator can be used to dynamically federate with many external OpenID Connect Providers. The OIDC Authenticator requires a few options to work properly and these are summarized below:

Configuration optionDescription
configuration-urlThe URL of the OIDC metadata endpoint. E.g., https://idsvr.example.com/oauth/.well-known/openid-configuration
client-id and client-secretThe ID and secret of the client configured in the external provider.
http-clientThe ID of the HTTP client that will be used to call the external provider, e.g., to get the metadata or exchange the authorization code for tokens.

Properly Secure Client Secrets

One entry that the configuration API returns is the client secret. The secret is sent to the Curity Identity Server in plain text, but you should take proper care when storing those secrets. Either access to the configuration API and its database should be restricted, or you should encrypt those secrets.

The authenticator also accept other options, that are not mandatory, for example:

  • If use-subject-for-login-hint is set to true then the OIDC Provider will get a login hint that contains the current subject attribute. (The value of the subject attribute at the time when the Dynamic Authenticator is called in the authentication flow.)
  • The scope attribute can contain a space-separated list of scopes that should be requested from the OIDC Provider.

The response from the configuration API might thus look similar to this:

{
    "configuration-url": "https://idsvr.example.com/oauth/.well-known/openid-configuration",
    "client-id": "federation-client",
    "client-secret": "Password1",
    "http-client": "https-client",
    "scope": "openid profile",
    "use-subject-for-login-hint": true
}

Make sure that the HTTP client with the ID referenced in the configuration exists in the Facilities > HTTP Clients section of the Curity Identity Server's configuration. It is best to use just a few clients for all the federated providers as creating a client for every provider will complicate management of the dynamic authentication. Very often you will need one HTTP Client, unless some of your providers would require different timeout settings. You will also need separate clients if you would have a few high-security providers, where mutual TLS would be used to connect.

As the Curity Identity Server makes direct HTTP calls to the external providers, the providers' certificates must be trusted by the Curity Identity Server. Make sure that the HTTP client is configured to use trust stores and that your providers' certificates are added to the Curity Identity Server's configuration in Facilities -> Crypto -> Server Trust Stores. As there might be a lot of providers used by the Dynamic Authenticator, it's best to add certificates of issuers (Certificate Authorities), not the providers themselves, so that one entry can establish trust for numerous entities.

HTTP Client with configured trust stores

Redirect URI for the Federated Provider

When registering a client at the Federated Provider you will need to provide a redirect URI to the Curity Identity Server. This URI is based on your Curity Identity Server's base URL, the authentication endpoint settings and the authenticator's name. It has the following form:

$BASE_URL/$AUTHENTICATION_ENDPOINT/$AUTHENTICATOR_NAME/callback

For example:

https://idsvr.example.com/authn/authentication/dynamic1/callback

The path for the $AUTHENTINCATION_ENDPOINT is set in Profiles -> Authentication Service -> Endpoints.

Configuring the Dynamic Authenticator

Follow these steps to configure a Dynamic Authenticator in the Curity Identity Server.

  1. Go to Profiles -> Authentication Profile -> Authenticators and click on + New Authenticator.
  2. Enter a suitable name and select the Dynamic type.

New Dynamic Authenticator

  1. Choose the Delegate Implementation Type, e.g., oidc
  2. Select the type of Configuration Source:

The configuration for delegate authenticators will be read from a web service using an HTTP request. The API should accept the GET method with two query parameters and respond with a JSON response. The parameters are:

  • fid — the federated provider's ID
  • imp — the implementation type of the delegate authenticator (e.g., oidc)

Web Service configuration

Fill the configuration fields:

  • Hostname — the host of the configuration API
  • Port — the port of the configuration API
  • Context — the path to the configuration endpoint
  • HTTP Client — the HTTP client that will be used to call the API. The client can be configured to use authentication, e.g., Basic Authentication or mutual TLS

The configuration for delegate authenticators will be read from a bucket defined by the given datasource. The implementation of the bucket depends on the chosen data source. This might be a table in the primary database, a separate key-value store, a JSON-based REST service, etc.

The value kept in the bucket should be the JSON with the delegate authenticator's configuration. The entry's subject is the federated provider's ID. The entry's purpose is the delegate authenticator's implementation type.

Bucket configuration

  1. Commit changes.

Federation ID Prerequisite

The Dynamic Authenticator must choose which federated provider should be used in the concrete authentication flow. This decision is based on the incoming context attribute dynamic-authenticator-federation-id. This attribute should contain the ID of the federation that will be used in the authentication flow. The value default is used if no attribute is provided to the Dynamic Authenticator.

One way of setting this attribute is to have a prerequisite username authenticator that collects the user's login, then extracts the domain part of the login using a script transformer action. This solution is implemented in the demo described below.

Example Implementation

The Dynamic Authenticator Demo contains resources that will allow you to quickly start up an instance of the Curity Identity Server with the Dynamic Authenticator configured. The demo also spins up an API that serves the configuration and two additional instances of the Curity Identity Server that serve as external OIDC providers.

The providers are configured with custom SSL certificates signed by the same CA (self-signed). The CA certificate is then added to the main instance's trust store so that communication can be established between all parties.

Prerequisites

To run the demo you will need the following tools installed on your machine:

  • Docker desktop
  • openssl
  • curl

You will also need a license for the Curity Identity Server. If you don't have one you can get a trial license from the Curity Developer portal.

Run the Demo

To start the demo, follow these steps:

  • Copy the license JSON file to the idsvr folder.
  • Add the following line to your /etc/hosts file:
127.0.0.1 provider1.example.com provider2.example.com
  • Run the ./deploy.sh script. The script will create necessary certificates and will start all the containers required by the demo.

Once you're done with the test, run the ./teardown.sh script to free all resources.

Testing the Solution

You can log in to the main instance of the Curity Identity Server, by starting an OAuth flow for the client dynamic-authenticator-demo, e.g., navigate your browser to: https://localhost:8443/oauth/v2/oauth-authorize?client_id=dynamic-authenticator-demo&response_type=code&scope=openid&redirect_uri=http://localhost. (You can use OAuth.tools to perform OAuth flows, but you will need to expose the main instance of the Curity Identity Server to the Internet. Here is a tutorial that shows how to do it using a free tool called ngrok.)

You will see an authentication method selection screen. Choose Dynamic Authenticator.

Authentication selector

You will see the username authenticator screen. Type user1@provider1 or user2@provider2 to be redirected to the corresponding provider.

Username prerequisite authenticator

Proider 1 login screen

At provider1 you can log in with user1/Password1. At provider2 log in with user2/Password1.

After logging in with a provider you will see the Debug Attribute Action screen, where you can study the attributes collected from the respective provider. Note that even though userX@providerX was first used as the subject, the final subject is the one obtained from the provider.

Adjust Providers' Theme with the Look And Feel Editor

The Look And Feel editor provides a way of changing the theme of the login forms without the need of editing CSS files and templates. You can use it to quickly change the login screens look.

Conclusion

The Dynamic Authenticator provides a great way for managing a situation where the Curity Identity Server needs to federate with numerous external Identity Providers. If you federate with a couple dozen or hundreds of Identity Providers then it will be much more efficient to use the Dynamic Authenticator, instead of having to configure all the federations as separate authenticators directly in the Curity Identity Server's configuration.