Dynamic Authenticator

Dynamic authenticators are authenticators that delegate authentication execution to another authenticator which can be configured dynamically.

The dynamic configuration for the delegate authenticator may be obtained by Curity from an external source, as we’ll see later, rather than from the Configuration Service as with conventional authenticators.

The main use-case for dynamic authenticators is supporting Federation-based authentication. For example, it is possible to configure a dynamic authenticator that, depending on the username of the user starting an authentication flow (which can be collected by a pre-requisite username authenticator), uses a different OpenID Connect provider or Credential Manager to actually authenticate the user.

Configuration

Dynamic authenticators have a static Authenticator Base Configuration, as all authenticators, but also:

  • Shared Delegate Authenticator Settings.
  • Delegate Authenticator Details

The Authenticator Base Configuration is inherited by the delegate authenticator, while the Shared Delegate Authenticator Settings are made available to the delegate authenticator’s configuration loader, which may then use that to transform the loaded configuration.

Shared Delegate Authenticator Settings

These settings are meant to be used by the delegate plugin configuration loader to transform the loaded configuration. In other words, they are not part of the delegate authenticator’s configuration.

Currently, this includes only one setting:

  • Keystore Password

This setting allows a delegate plugin whose dynamic configuration includes a keystore to keep the password to decrypt such keystore in the Dynamic Authenticator’s configuration, rather than together with the dynamic configuration.

Note

Keeping the password together with the encrypted keystore in the dynamically loaded configuration would make the password pointless.

As with all secrets, Curity automatically encrypts the value of this setting when exporting its configuration.

Currently, only the SAML2 plugin uses this setting.

Delegate Authenticator Details

The Dynamic Authenticator requires the following settings to identify and load a delegate plugin:

  • the type of the delegate authenticator plugin.
  • the source of the delegate authenticator’s configuration.

The following sections explain these settings in more detail.

Delegate Authenticator

The delegate authenticator is responsible for performing the actual user authentication and is configured according to the dynamic configuration fetched for it for each federation.

The following authenticator types are currently supported:

  • oidc (OpenID Connect)
  • saml2 (SAML2)
  • html-form (currently supported for testing only)

Dynamic Configuration Source

The configuration for the delegate authenticator must be provided by an external source.

The following can provide dynamic authenticator’s configuration:

In both cases, two parameters are provided as “keys” for fetching the configuration to be used:

  • the federation ID, a string representing the realm the user authenticates under.
  • the implementation type of the delegate authenticator (e.g. oidc).

The federation ID is expected to be part of the subject attributes under a key called dynamic-authenticator-federation-id. If not present, the value default is used.

See Example Use-case for an example of how to set this attribute.

The response must be provided using the configuration schema for the relevant delegate authenticator, excluding the base settings (the Dynamic Authenticator’s Base Settings are always used for all delegate authenticators).

The plugin-specific configuration should be the root of the response object. See an example in the Web Service section below.

Curity caches responses for a particular combination of federation ID and implementation-type few hours to avoid reloading configuration too often.

Bucket Dynamic Configuration Source

The parameters are provided as follows:

  • subject is the federation ID.
  • purpose is the delegate authenticator’s implementation type.

Web Service Configuration Source

The parameters are provided as follows:

  • fid query parameter is the federation ID.
  • imp query parameter is the delegate authenticator’s implementation type.

Web Services must provide the response using the application/json media type.

Example request for dynamic configuration:

GET https://example.org:8888/dynamic-conf?fid=default&imp=oidc
Accept: application/json

Example JSON response body for a oidc delegate authenticator:

{
    "configuration-url": "https://example.org:8888/.well-known/openid-configuration",
    "client-id": "oauth-client-id",
    "client-secret": "data:text/plain;aes,v:S.TTdUVGFTUG1PSWJNN3B1Zg==.NmvU8FRhq0kTj-wguiCZxg==.e_a3d6iTdUpVK0rzBDRh4Q==.5tKEIn_chCo_1pjE9FuZy1MZ4qt_6c1i-Y_F2cI2ogM=",
    "http-client": "http-client-id",
}

Example request for dynamic configuration:

GET https://example.org:8888/dynamic-conf?fid=samlfederation&imp=saml2
Accept: application/json

Example JSON response body for a saml2 delegate authenticator:

{
    "issuer-entity-id": "https://curity.example.com/sp",
    "force-auth": "always",
    "idp-entity-id": "https://external.example.com/idp",
    "idp-url": "https://external.example.com/idp/authenticate",
    "signature-verification-key": "default-signature-verification-key"
}

Note

the easiest way to find out what the configuration object looks like for a particular authenticator type is to configure the authenticator using the Web UI, then click on View XML at the top-right of the screen, then customize the data as needed.

Care must be taken to ensure that any elements referenced to from the dynamic configuration actually exist in the server configuration. For example, the configuration above would require that there exists a http-client with ID http-client-id in the static server configuration. If that is not the case, the configuration will fail validation and all authentication attempts will result in an error.

Configuration Example

<authenticator>
    <id>dyn1</id>
    <description>Dynamic authentication</description>
    <previous-authenticator>collect-username</previous-authenticator>
    <dynamic xmlns="https://curity.se/ns/conf/authenticators/dynamic">
        <delegate-implementation-type>oidc</delegate-implementation-type>
        <!-- could be a configuration-bucket instead -->
        <configuration-web-service>
            <hostname>example.org</hostname>
            <port>8888</port>
            <context>/dynamic-conf</context>
            <http-client>http-client-id</http-client>
        </configuration-web-service>
    </dynamic>
</authenticator>

Example Use-case

An example use-case for Dynamic Authenticators could go like this:

  • Create a Dynamic Authenticator that delegates to an oidc authenticator.
  • Configure a previous-authenticator to collect the username.
  • Configure a Script Transformer Action to store the collected username in the authentication attributes.
  • The script transformer (example below) adds the chosen federation ID to the dynamic-authenticator-federation-id attribute.
  • Make a configuration source available that knows how to map a federation ID and authenticator type to the correct oidc authenticator configuration.
Listing 106 Example transformation script to select a federation ID based on user’s email address.
    function result(context) {
        var attributes = context.attributeMap;
        var sub = attributes.subject;
        var indexOfAt = sub.indexOf('@');

        // federationId which will be sent to the external configuration source
        var federationId = indexOfAt >= 0 ? sub.substring(indexOfAt + 1) : 'default';

        // the dynamic authenticator will look at this attribute for the federation ID,
        // or use 'default' if it's not found.
        attributes['dynamic-authenticator-federation-id'] = federationId;

        return attributes;
    }

When the Dynamic Authenticator executes, it will load the configuration (from the cache if available) for the particular federation ID added by the script transformer (which should have run after the previous-authenticator), generate an instance of the OIDC Authenticator with that configuration, and then delegate the authentication flow to the newly-configured OIDC Authenticator.