Step-up auth: Include condition for id token claims [PART 1.1]

What does this MR do and why?

The related issue description contains the motivation for this MR.

This commit introduces the included condition for step-up authentication. This condition allows to specify which ID token claims must be included for successful authentication. The included condition complements the existing required condition by enabling more flexible ID token claim validation. For example, it allows specifying that a claim must include one or more values from a predefined list, such as amr: ['mfa', 'fpt'] for multi-factor authentication.

This enhancement ensures compatibility with identity providers like Microsoft Entra ID, which rely on claims like acrs to implement step-up authentication flows. It also improves security by enabling fine-grained control over authentication requirements.

Changelog: added

🛠️ with ❤️ at Siemens

References

Screenshots or screen recordings

There are not frontend changes.

How to set up and validate locally

Note: Configuring and preparing the test setup with MS Entra ID is quite hard, e.g. you need a certain fee-based licence for MS Entra ID, configure conditional access policies, etc. It is much easier and sufficient to configure Keycloak as a "fake MS Entra ID" to return a custom ID token claim acrs (as done by MS Entra ID). This is why, the following steps refer to Keycloak and not MS Entra ID.

Part 1: Configure step-up auth in Keycloak (as MS Entra ID)

  1. I recommend to create a new Keycloak realm step-up-auth-gitlab-ms-entra-id-testing in order to avoid any conflicts with the other step-up auth Keycloak config; the following steps should be configured inside the new Keycloak realm
  2. In the new Keycloak realm, follow the steps described in the initial step-up auth MR "Part 1: Configure step-up auth in Keycloak as done in the previous MR
  3. Go to the details of the Keycloak client (created in the previous step) => Select the tab "Client scopes" => Select the client scope that ends with xxxx-dedicated
  4. Go to "Realm settings" and adjust the keys in the section "ACR to LoA Mapping" as shown in this screenshot
  5. Add a new ID token claim custom_claim_step_up_auth_state (by clicking Add mapper => By configuration => Claims parameter with value ID Token)
    • Field Name => custom_claim_step_up_auth_state
    • Field Claim name => custom_claim_step_up_auth_state
  6. Add a new ID token claim custom_claim_acrs (by clicking Add mapper => By configuration => Hardcoded claim )
    • Field Name => custom_claim_acrs
    • Field Token claim name => custom_claim_acrs
    • Field Claim value => ["c20", "urn:user:registersecurityinfo", "c25"]
    • Field Claim JSON Type => JSON

Here is screencast that shows the Keycloak settings: https://www.loom.com/share/967ad9a995f0415ca813543612216907

Screenshot from the Keycloak config

grafik

grafik

Part 2: Prepare your local GitLab gdk instance

  1. Follow the steps described in the initial step-up auth MR "Part 2: Prepare your local GitLab gdk instance", e.g. enable admin mode, enable feature flag :omniauth_step_up_auth_for_admin_mode, create admin user in GitLab that matches the Keycloak user
  2. In your local gdk instance, add the following omniauth configuation to the config/gitlab.yml, see collapsed section below
  3. Restart your local gdk instance
Click to expand the `config/gitlab.yml`
development:
  <<: *base
  omniauth:
    allow_bypass_two_factor:  ["oidc_keycloak_ms_entra_id_testing"]
    allow_single_sign_on: ["oidc_keycloak_ms_entra_id_testing"]
    auto_link_ldap_user: null
    auto_link_saml_user: null
    auto_link_user: ["oidc_keycloak_ms_entra_id_testing"]
    auto_sign_in_with_provider: 
    block_auto_created_users: false
    external_providers: []

    providers:
    - { name: "oidc_keycloak_ms_entra_id_testing",
        label: "[OIDC] Keycloak (MS Entra ID config)",
        args: {
          name: "oidc_keycloak_ms_entra_id_testing",
          strategy_class: "OmniAuth::Strategies::OpenIDConnect",
          scope: ["openid", "profile", "email"],
          response_type: "code",
          issuer: "http://keycloak.test:8080/realms/step-up-auth-gitlab-ms-entra-id-testing",
          client_auth_method: "query",
          discovery: false,
          uid_field: "preferred_username",
          pkce: true,
          allow_authorize_params: ["claims"],
          client_options: {
            host: "keycloak.test",
            scheme: "http",
            port: "8080",
            identifier: "step-up-auth-gitlab-ms-entra-id-testing-client",
            secret: "<<CLIENT_SECRET>>",
            redirect_uri: "http://gdk.test:3000/users/auth/oidc_keycloak_ms_entra_id_testing/callback",
            authorization_endpoint: "/realms/step-up-auth-gitlab-ms-entra-id-testing/protocol/openid-connect/auth",
            token_endpoint: "/realms/step-up-auth-gitlab-ms-entra-id-testing/protocol/openid-connect/token",
            userinfo_endpoint: "/realms/step-up-auth-gitlab-ms-entra-id-testing/protocol/openid-connect/userinfo",
            jwks_uri: "http://keycloak.test:8080/realms/step-up-auth-gitlab-ms-entra-id-testing/protocol/openid-connect/certs",
            end_session_endpoint: "/realms/step-up-auth-gitlab-ms-entra-id-testing/protocol/openid-connect/logout"
          }
        },
        step_up_auth: {
          admin_mode: {
            id_token: {
              required: {
                acr: 'c25',
                custom_claim_step_up_auth_state: "requested"
              },
              included: {
                custom_claim_acrs: 'c25'
              }
            },
            params: {
              claims: { 
                id_token: { 
                  acr: { 
                    essential: true, 
                    values: ['c25'] 
                  }, 
                  custom_claim_step_up_auth_state: { 
                    essential: true, 
                    value: "requested"
                  } 
                } 
              }
            }
          },
        }
      }

Part 3: Test the step-up auth for admin mode with include condition

  1. Open a private browser window (fresh session)
  2. Go to the usual sign in page: http://gdk.test:3000/users/sign_in
  3. Use the configured Keycloak OIDC omniauth provider "[OIDC] Keycloak (MS Entra ID config)" to sign in; you will be redirected to Keycloak sign in interface
  4. In Keycloak, submit the username and password; Note: this is the normal sign in for the user (think of it as the first step and not the step-up auth)
  5. After a successful sign in, the user will be redirected to it's dashboard
  6. Try to "Enter admin mode": http://gdk.test:3000/admin/session/new (this should be possible because the user is also an admin)
  7. Sign in with the button "[OIDC] Keycloak (MS Entra ID config)" (triggering step-up auth in Keycloak by passing request params) => you will be redirected to Keycloak interface
  8. In Keycloak, you will be asked to authenticate for a higher step; Note: this is the additional step that requires higher authentication, i.e. the step-up auth
  9. After the successful second "stepped-up" sign in, the user will be redirected back to GitLab and the admin mode will be enabled

Note: GitLab allows the user to pass because the ID token claim custom_claim_acrs includes the value c25. In !171643 (merged), GitLab only allowed an exact match of the ID token claim.

MR acceptance checklist

Please evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

MR Checklist (@gerardo-navarro)

Related to #474650 #535861

Edited by Gerardo Navarro

Merge request reports

Loading