Skip to main content

# Integration with IdP provider

The BAF system allows you to configure integration with an IdP provider via the OIDC protocol to enable authentication and authorization through an external user source.

The system itself does not store any data of such external users – all user information is obtained during the OIDC flow, resulting in a short-lived cookie for interacting with the BAF dashboard. Currently, only the `Authorization Code` flow is supported.

Additionally, the system relies on the IdP provider for mapping roles, users, and workspaces. The roles and their privileges are created inside BAF, but the relationship "role – user – workspace" must be defined on the IdP side.

Thus, the integrator's task is to properly transfer and maintain consistency of workspaces and roles between the IdP and BAF. It is assumed that new accounts and roles are created infrequently, so synchronization is not performed often.

For more information follow Role Model section.

If you do not require IdP integration, you can skip its configuration and keep the default delivery settings.

## IdP preparation​

Before configuring BAF, you need to prepare the IdP. Let's walk through the process using Keycloak as an example.

### Creating a realm​

For managing BAF users, we recommend creating a separate `realm` to ensure that the integration with BAF does not interfere with other integrations.

### Creating a client​

After creating a separate `realm`, create a `client` that will be used by BAF to interact with Keycloak.

The client type must be OpenID Connect, and you also need to choose a client-id. In this example, we use `baf-client`.

BAF is considered a confidential client, so client authentication must be enabled. Leave the other toggles as shown in the image.

Next, configure the redirect URL validation. For this example, assume BAF is deployed at `https://127.0.0.1:8090`. The recommended URL configuration is shown below:

Note that your system domain may differ, but the redirect path always matches `/signin-idp/*` because this path is hardcoded inside BAF.

As a result of these operations, a new client will be created through which BAF will interact with Keycloak.

### Role mapping​

As mentioned earlier, the task of binding roles and accounts to users lies with the IdP provider. You need to build a convenient system for adding information about roles and workspaces to IdP users, for later transformation into token claims and parsing inside BAF.

The BAF system must unambiguously understand what type of role is bound to which account and user.

To do this, it parses the claims received during IdP user authentication, forms a set of roles from them, and stores all this information in a short-lived cookie, which is then used by BAF for authentication and authorization.

We will describe a role system based on Keycloak user attributes, but you may use any other way of forming claims that is convenient for you. In this system, each user inside the `realm` gets a set of attributes.

Each attribute indicates whether a role is present: for global roles – simply the presence or absence, and for local roles – in which workspace the role is active.

note

Roles have unique names, and mapping is performed by name.

### User attributes​

First, let's create an attribute for the standard global role `SuperAdmin`. Any other custom role that should work in a global context is configured similarly.

Go to Realm Settings, the User Profile tab, and click `Create Attribute`.

The attribute creation page opens. You can mostly configure the attribute as you like. The attribute name here is only visual and does not affect mapping. The most important part is to correctly configure Validators and Annotations.

- In Validators, select the `options` type with two values: `true` and `false`.
- In Annotations, select `select-radiobuttons`.

As a result, each user in the `realm` will have an attribute indicating whether they have the global `SuperAdmin` role.

note

To configure local roles, you need to retrieve a list of existing workspaces. The easiest way to do this is via the Workspaces page, which is available to users with the `SuperAdmin` role. It is recommended that you first configure the mappings for the `SuperAdmin` role and assign it to the appropriate user, then return to this section and configure the local roles.

Now let's configure an attribute for a local role, for example, `ApplicantReader`. Click `Create Attribute` again.

On the attribute configuration page, also set Validators and Annotations — the rest is up to you.

- In Validators, select two types: `multivalued` (to allow multiple values) and `options` with the workspace IDs (you can copy them from the Workspaces page opened by a user with the `SuperAdmin` role).
- In Annotations, select `multivalue`.

note

When adding a new workspace, update the `options` for all local role attributes.

As a result, each user in the `realm` will have an attribute indicating whether they have the `ApplicantReader` role in any workspaces.

### Claim mapping​

After creating the attributes, you have enabled the ability to assign roles to users, but BAF still will not see them. To expose custom attributes, set up their mapping to claims. To do this, go to the Client Scopes tab in the client you created earlier and select the scope described as "Dedicated scope and mappers for this client".

Next, add mappers for the new attributes. Let's start with the global role `SuperAdmin`.

Click Add Mapper → By Configuration and select User Attribute from the list.

Configure the attribute:

- User Attribute – select the previously created `SuperAdmin` attribute from the list.
- Token Claim Name – specify the claim key format. It is important to remember this format, as it will be used in the role data parsing logic on the BAF side. In this example, use `grole-<role name inside <ShortProductName/>>`, i.e. `grole-SuperAdmin`.
- Claim JSON Type – select `string`.
- Add to ID token, Add to access token, Add to userinfo, Add to token introspection – keep them enabled.

As a result, a claim with key `grole-SuperAdmin` and value `true` or `false` will be generated.

Now configure a mapper for the local role `ApplicantReader`. The configuration is similar, except for the `Multivalued` option being enabled and a different claim key pattern (field Token Claim Name): `role-<role name inside <ShortProductName/>>`, i.e. `role-ApplicantReader`.

As a result, a claim with key `role-ApplicantReader` and the workspace UUID as its value will be generated. If there are multiple workspaces, multiple claims with the same key and corresponding UUIDs will be produced.

note

It is important to understand the format in which claims are passed to BAF to correctly configure the parsing rules.

## Configuring IdP integration in BAF​

### Chart values configuration​

To configure the integration, you need to fill in the `idp` section in the `./values.baf.yaml` file.

Description of the section fields:

- `enable` – whether IdP integration is enabled. Set to `true`.
- `url` – the URL of the created `realm` inside the IdP. Based on the example (Keycloak deployed at `127.0.0.1:8080`), the URL would be `http://127.0.0.1:8080/realms/baf/`. If using a secure transport, specify `https` instead of `http`.
- `claimParseRules` – rules for parsing claim keys and values.
- `Idp__Debug` – debug mode for the IdP authentication mechanism. Setting `true` enables special logging to track which claims are received from the IdP and how they are parsed.
- `Idp__UserIdPrincipalName` – the claim name used as the user ID source. It is recommended to keep the default value and change it only if issues arise.
- `Idp__UsernamePrincipalName` – the claim name used as the user name source. It is recommended to keep the default value and change it only if issues arise.
- `Idp__ClientId` – the client ID created in the IdP that will be used by BAF.
- `Idp__ClientSecret` – configuration of the Kubernetes secret containing the client authentication secret.
- `Idp__RequireHttps` – a flag indicating whether HTTPS is required for IdP communication. For testing you can set `false`, but for production it must be `true`.

Example configuration based on the IdP preparation example:

    idp:
      enable: "true"
      url: "http://127.0.0.1:8080/realms/baf/"
      claimParseRules:
        - KeyRule: 'role-<roleName>'
          ValueRule: '<workspaceId>'
        - KeyRule: 'grole-<roleName>'
          ValueRule: '<enabled>'
      envOverride:
        Idp__Debug:
          value: "true"
        Idp__ClientId:
          value: "baf-client"
        Idp__RequireHttps:
          value: "false"

### Composing parsing rules​

The BAF system uses its own syntax for parsing claims. Recall that a claim consists of two parts: key and value. Both may contain useful data, so a parsing rule consists of two parts: a key rule (`KeyRule`) and a value rule (`ValueRule`).

The syntax is as follows: everything outside the `<` and `>` characters is structural data and must exactly match the text in the rule for it to apply. Everything inside angle brackets is captured into variables with the same names.

There are three variables:

- `roleName` – the role name.
- `workspaceId` – the workspace ID where the role applies.
- `enabled` – a flag indicating whether the claim is active. It must be a boolean (string `true` or `false`). This flag allows ignoring a claim if the IdP always sends it even when empty.

Multiple rules can be defined. This is convenient if the claim formats for global and local roles differ. All claims received from the IdP are checked in order against each rule. As soon as a claim's key and value match a rule, the check for that claim stops, and the system moves to the next claim.

The logic for processing parsed data is as follows:

- If both `roleName` and `workspaceId` are populated, a local role is added for that workspace.
- If only `roleName` is populated, a global role is added.
- If `enabled` is set to `false`, the claim is ignored even if parsed successfully.

### Examples​

Consider a rule for a local role:

    KeyRule: 'role-<roleName>'
    ValueRule: '<workspaceId>'

This rule will parse the claim `role-SuperAdmin: cb58a1f2-2985-4d9f-94b6-dc6ce03e2ca7` into:

- `roleName` = `SuperAdmin`
- `workspaceId` = `cb58a1f2-2985-4d9f-94b6-dc6ce03e2ca7`

The claim `rrole-SuperAdmin: cb58a1f2-2985-4d9f-94b6-dc6ce03e2ca7` will be ignored because the key does not match.

note

Be aware that a rule consisting solely of variables (e.g., `ValueRule: '<workspaceId>'`) will match any string. However, this may lead to errors: for example, a claim `role-SuperAdmin: workspaceId-cb58a1f2...` would capture `workspaceId-cb58a1f2...` as the workspaceId, which is not a valid UUID and will cause an error.

Now consider a rule for a global role:

    KeyRule: 'grole-<roleName>'
    ValueRule: '<enabled>'

This rule will parse the claim `grole-SuperAdmin: false` into:

- `roleName` = `SuperAdmin`
- `enabled` = `false`

If `enabled` is missing, it is automatically set to `true`.

### Debug mode​

When debug mode is enabled for the IdP integration, any authentication attempt through IdP will generate additional logs inside the `baf-dashboard-dep` pod.

First, the logs output information about the user from the service claims, whose keys are defined by `Idp__UserIdPrincipalName` and `Idp__UsernamePrincipalName`:

    Start parsing claims
    User Id: 73254712-90c5-41ff-96e4-8c5e7e79185e
    User name: bafk

Then, the logs list all claims received from the IdP in the format `key: value` and the rules (in `KeyRule ValueRule` format, as set in `claimParseRules`) that were checked for each claim.

Example of claims not recognized by any rule:

    - Claim: http://schemas.microsoft.com/claims/authnclassreference: 1
        Check rule: role-<roleName> <workspaceId>
        Check rule: grole-<roleName> <enabled>
    - Claim: email_verified: false
        Check rule: role-<roleName> <workspaceId>
        Check rule: grole-<roleName> <enabled>

If a rule matches, the variables captured from the key and value are printed.

note

Note that both the key and the value must be successfully parsed, otherwise the claim is skipped.

Example of a claim recognized as a global role:

    - Claim: grole-superAdmin: true
        Check rule: role-<roleName> <workspaceId>
        Check rule: grole-<roleName> <enabled>
        Key parsed.
        Current data:
            Role: superAdmin
            Enabled: True
            Workspace id:
        Value parsed.
        Current data:
            Role: superAdmin
            Enabled: True
            Workspace id:
    Add global role: SuperAdmin.

Example of a claim recognized as a local role:

    - Claim: role-Applicant Reader: 656309de-e5e8-471c-a2b3-7f9ac32ba5ee
        Check rule: role-<roleName> <workspaceId>
        Key parsed.
        Current data:
            Role: Applicant Reader
            Enabled: True
            Workspace id:
        Value parsed.
        Current data:
            Role: Applicant Reader
            Enabled: True
            Workspace id: 656309de-e5e8-471c-a2b3-7f9ac32ba5ee
    Add workspace role: Applicant Reader. Workspace ID: 656309de-e5e8-471c-a2b3-7f9ac32ba5ee.