Step-up auth: Add omniauth step-up auth for admin mode [PART 1.0]
-
Please check this box if this contribution uses AI-generated content (including content generated by GitLab Duo features) as outlined in the GitLab DCO & CLA. As a benefit of being a GitLab Community Contributor, you can request access to GitLab Duo.
What does this MR do and why?
Step-up authentication is a security feature that requires additional verification for accessing sensitive data or performing critical actions.
This commit introduces step-up authentication for the admin mode and includes the following aspects:
- Extend configuration of omniauth providers in GitLab config
gitlab.yml
to allow the definition of required and included ID token claims. - Extract the ID token claims when the user signs in successfully through the omniauth provider
- Check for required ID token claims and enforc step-up auth before accessing admin area
- Hide feature behind feature flag
:omniauth_step_up_auth_for_admin_mode
- Extend documentation for step-up auth configuration
The sequence diagram in the collapsed section shows the flow and how the session is set.
Click to expand the sequence diagram
sequenceDiagram
actor user as User
participant gitlab as GitLab
participant idp as IdP<br/>(e.g. Keycloak)
user->>gitlab: User is signed in and works in GitLab
user->>+gitlab: Goes to the admin area<br/>Re-authentication with step-up is required.
Note over user,idp: When accessing an admin route <br/> then the step-up auth session is checked<br/>if step-up auth has been done successful.<br><br> Currently, there is no step-up auth session has available (it is empty).<br/>Therefore, GitLab will redirect the user to the new_admin_session_path.
gitlab->>-user: REDIRECT 302 to /admin/session/new
user->>+gitlab: /user/auth/oauth_provider - User clicks chooses the available IdP (configured for step-up auth)
Note over gitlab: GitLab sets step-up auth session data to<br>{ 'omniauth_step_up_auth' => { 'openid_connect' => { 'admin_mode' => { 'state' => 'requested' } } }
Note over user, idp: Finally, GitLab redirects as usual to the IdP and<br>includes the specified step-up auth params.
gitlab->>-user: REDIRECT 302 to authorize endpoint of IdP
user->>+idp: authorize?acr_values='gold'&...
user->>idp: User interacts with IdP as usual and wins all authentication challenges.
Note over user, idp: When the user succeeds with all authentication challenges then the IdP redirects the user back to the callback url endpoint in GitLab.
idp->>-user: REDIRECT 302 to omniauth callback endpoint in GitLab
user->>+gitlab: /user/auth/oauth_provider/callback?...
Note over user,idp: GitLab receives the id token claims from the IdP and checks if the specified step-up auth conditions are fulfilled.<br>If yes, then GitLab sets the state information in the step-up auth session hash to "succeeded"<br>If no, then GitLab sets the state information in the step-up auth session hash to "failed"<br><br>Finally, GitLab redirects the user to the admin page that the user wanted to access initially.
Note over gitlab: GitLab sets step-up auth session data to<br>{ 'omniauth_step_up_auth' => { 'openid_connect' => { 'admin_mode' => { 'state' => 'succeeded' } } }
gitlab->>-user: REDIRECT 302 to /admin/dashboard
user->>gitlab: /admin/dashboard
Note over gitlab: GitLab checks if the state value in the step-up auth session hash is set to "succeeded".<br> If this is the case, then the user is allowed pass.<br>Otherwise, the user will be redirected to new_admin_session_path again.
References
Please include cross links to any resources that are relevant to this MR This will give reviewers and future readers helpful context to give an efficient review of the changes introduced.
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)
-
Changelog entry added, if necessary -
Documentation created/updated via this MR -
Documentation reviewed by technical writer or follow-up review issue created -
Tests added for this feature/bug -
Tested in all supported browsers -
Conforms to the code review guidelines -
Conforms to the merge request performance guidelines -
Conforms to the style guides -
Conforms to the javascript style guides -
Conforms to the database guides -
Add test cases for 'when step-up authentication entries exist in session' -
Add test case for admin controller when step-up authentication is enabled -
Add subject when checking for feature flag :omniauth_step_up_auth_for_admin_mode
Screenshots or screen recordings
Scenario: Successful step-up auth challenge
Screencast: https://www.loom.com/share/dfc25a15b0944b8cbf03426ce8ab9ed6
This scenario shows what happens when the step-up auth challenge is successful:
- The screencast starts with a clean session in a private browser window.
- The user performs a normal sign in via the OIDC omniauth provider (this is not the step-up auth).
- After the "normal" sign in, the user wants to go to the admin area and is asked for a reauthentication. This reauthentication can only be achieved through a step-up authentication.
- The use clicks on the button "OpenID Connect" and is redirected to the IdP server (Keycloak) to perform a step-up authentication. Note: In case of this screencast, the step-up auth method is configured to be a second password prompt, but in production, it would be a more secure auth method, e.g. fingerprint, device trust, etc.
- Successful step-up auth challenge implemenation
Click to expand the step-up auth config in `config/gitlab.yml`
step_up_auth: {
admin_mode: {
enabled: true,
id_token: {
required: {
acr: 'gold'
}
},
params: {
claims: {
id_token: {
acr: {
essential: true,
values: ['gold']
}
}
}
}
}
}
Scenario: Failed step-up auth challenge
Screencast: https://www.loom.com/share/ba71ffdbcb0a4f0a9d928a00163d96ca
This scenario shows what happens when the step-up auth challenge fails because the omniauth config is misconfigured, i.e. the required acr
value must be gold
, but the authorization parameters wants Keycloak to authenticate the user with the acr
value silver
Here are more information regarding the screencast:
- After a successful step-up authencation, the admin mode for the user is activated and the user can access the admin area.
- Then, we adjust the
gitlab.yml
to still require theacr
valuegold
for accessing the admin mode, but we remove the section regarding the request query params that are necessary to trigger the step-up auth on the IdP side. - This time, when we want to sign in to the admin area, the user is redirected to the IdP without the request param regarding the desired
acr
values => the IdP checks the user and authenticates the user successfully because no step-up is requested and needed - The IdP redirects back to the GitLab and GitLab identifies that the user does not have the required
acr
value "gold" (that is required to access the GitLab admin area) => hence, GitLab shows the alert that a higher auth context (acr) is required, see screenshot
Click to expand the step-up auth config in `config/gitlab.yml`
step_up_auth: {
admin_mode: {
enabled: true,
documentation_link: "https://openid.net/specs/openid-connect-core-1_0.html#IDToken",
id_token: {
required: {
acr: 'gold'
}
}
}
}
Further scenarios to test
- Admin user is able to access any other non-admin page as usual
- Admin user is or is not connected to the identity of the oauth provider that is configured for step-up auth; in other words, when the admin user does not login via an oauth provider then the admin user should be able access the admin mode (area).
- Step-up auth config is enabled or not
- Step-up auth requirements are fulfilled or not
How to set up and validate locally
Part 1: Configure step-up auth in Keycloak
- Start local keycloak instance using docker compose, see an examplary
docker-compose.yml
in collapsed section below - Follow the steps to configure step-up auth in Keycloak; please look into the documentation section (
oidc.md
) that is part of this MR; this includes:
- In Keycloak, create a new realm, e.g.
step-up-auth-gitlab-realm
- In Keycloak, setup the LoA Mapping
- In Keycloak, setup a custom browser flow for step-up auth
- In Keycloak, create a client and register GitLab as an OIDC client
- In Keycloak, add new user to the realm; Note: the user email will be necessary for a following step
Click to see `docker-compose.yml`
---
services:
keycloak:
image: keycloak/keycloak:25.0
command: start-dev --log-level="org.keycloak.authentication:TRACE"
environment:
KEYCLOAK_ADMIN: admin
KEYCLOAK_ADMIN_PASSWORD: admin
ports:
- 8080:8080
volumes:
- ./keycloak/data:/opt/keycloak/data
Part 2: Prepare your local GitLab gdk instance
- In your local gdk instance, add the following omniauth configuation to the
config/gitlab.yml
, see collapsed section below - In the rails console, enable the GitLab admin mode
::Gitlab::CurrentSettings.update!(admin_mode: true)
- In GitLab, create a new admin user; Note that the user emails in GitLab and in Keycloak must match; Note that the user must be admin, otherwise the user will not be able to enter the admin mode / area.
- Open the rails console and enable the feature flag
:omniauth_step_up_auth_for_admin_mode
Feature.enable(:omniauth_step_up_auth_for_admin_mode)
Click to expand the `config/gitlab.yml`
development:
<<: *base
omniauth:
allow_bypass_two_factor: ["openid_connect"]
allow_single_sign_on: ["openid_connect"]
auto_link_ldap_user: null
auto_link_saml_user: null
auto_link_user: ["openid_connect"]
auto_sign_in_with_provider:
block_auto_created_users: false
external_providers: []
providers:
- { name: "openid_connect",
label: "[OIDC] Keycloak",
args: {
name: "openid_connect",
# strategy_class: "OmniAuth::Strategies::OpenIDConnect",
scope: ["openid", "profile", "email"],
response_type: "code",
issuer: "http://localhost:8080/realms/step-up-auth-gitlab-realm",
client_auth_method: "query",
discovery: false,
uid_field: "preferred_username",
pkce: true,
allow_authorize_params: ["claims"],
client_options: {
host: "localhost",
scheme: "http",
port: "8080",
identifier: "step-up-auth-gitlab-client",
secret: "C6S2b1ZkifZa6BI8Jy5K3lz2Eglb4JuQ",
redirect_uri: "http://gdk.test:3000/users/auth/openid_connect/callback",
authorization_endpoint: "/realms/step-up-auth-gitlab-realm/protocol/openid-connect/auth",
token_endpoint: "/realms/step-up-auth-gitlab-realm/protocol/openid-connect/token",
userinfo_endpoint: "/realms/step-up-auth-gitlab-realm/protocol/openid-connect/userinfo",
jwks_uri: "http://localhost:8080/realms/step-up-auth-gitlab-realm/protocol/openid-connect/certs",
end_session_endpoint: "/realms/step-up-auth-gitlab-realm/protocol/openid-connect/logout"
}
},
step_up_auth: {
admin_mode: {
enabled: true,
documentation_link: "https://openid.net/specs/openid-connect-core-1_0.html#IDToken",
id_token: {
required: {
acr: 'gold'
}
},
params: {
claims: {
id_token: {
acr: {
essential: true,
values: ['gold']
}
}
}
}
},
}
}
Part 3: Test the step-up auth for admin mode
- Open a private browser window (fresh session)
- Go to the usual sign in page: http://gdk.test:3000/users/sign_in
- Use the configured Keycloak OIDC omniauth provider to sign in; you will be redirected to Keycloak sign in interface
- 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)
- After a successful sign in, the user will be redirected to it's dashboard
- Go to the reauthentication page for the admin area: http://gdk.test:3000/admin/session/new (this should be possible because the user is also an admin)
- Sign in with the button "[OIDC] Keycloak"; Note: this is a sepcial omniauth sign in button (as part of this POC) that will trigger the step-up auth => you will be redirected to Keycloak interface
- 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
- After the successful second "stepped-up" sign in, the user will be redirected back to GitLab and the admin mode will be enabled
Related to #474650