Self-managed SAML Duo Seat Assignment
What does this MR do and why?
This merge request adds support for Duo add-on group assignment at the instance level for SAML authentication. Previously, Duo add-on assignment was only available at the group level, but now it can be configured globally through the GitLab configuration file. The changes introduce a new duo_add_on_groups setting in the SAML configuration that allows administrators to specify which SAML groups should automatically receive Duo add-on assignments.
When users authenticate via SAML, the system now checks if they belong to any of these designated Duo groups. If they do, they're automatically assigned a Duo seat; if they're removed from these groups, their Duo seat is automatically unassigned. This functionality is implemented through a new DuoAddOnAssignmentUpdater class that handles the assignment logic, with appropriate tests to verify the behavior under various conditions.
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.
Screenshots or screen recordings
Screenshots are required for UI changes, and strongly recommended for all other merge requests.
| Before | After |
|---|---|
How to set up and validate locally
Numbered steps to set up and validate the change are strongly suggested.
-
Configure your GDK for Duo: https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/development/ai_features/ai_development_license.md#option-b-local-license-with-rake-task-in-self-managed-mode-single-tenant-setup
-
Configure self-managed SAML including the new
duo_add_on_groupsoption.- { name: "saml", groups_attribute: 'Groups', duo_add_on_groups: ['Everyone'], args: { name: "saml", assertion_consumer_service_url: "https://gdk.test:3443/users/auth/saml/callback", ... issuer: "https://gdk.test:3443", } } -
Restart both
rails-webandrails-background-jobs. -
Sign-in as a SAML user that is in the configured add-on group. Observe that a Duo add-on seat has been assigned for the user.
[1] pry(main)> add_on = ::GitlabSubscriptions::Duo.enterprise_or_pro_for_namespace(nil) => #<GitlabSubscriptions::AddOnPurchase:0x00000003217fbce0 id: 1, created_at: Wed, 09 Apr 2025 19:45:38.974758000 UTC +00:00, updated_at: Wed, 09 Apr 2025 19:45:38.974758000 UTC +00:00, subscription_add_on_id: 3, namespace_id: nil, quantity: 10, expires_on: Fri, 20 Feb 2026, purchase_xid: "123456", last_assigned_users_refreshed_at: Wed, 09 Apr 2025 19:45:40.251987000 UTC +00:00, trial: false, started_at: Wed, 09 Apr 2025, organization_id: 1> [2] pry(main)> add_on.assigned_users => [#<GitlabSubscriptions::UserAddOnAssignment:0x0000000321a91e78 id: 3, add_on_purchase_id: 1, user_id: 201, created_at: Wed, 09 Apr 2025 20:10:52.218077000 UTC +00:00, updated_at: Wed, 09 Apr 2025 20:10:52.218077000 UTC +00:00, organization_id: 1>] -
If desired, repeat the processes but change parameters:
- Change the
duo_add_on_groupsto something your SAML test user is not a member of. Their assigned seat should be removed. - Remove the
duo_add_on_groupsconfiguration altogether and observe that the user's assigned Duo seat is not removed on sign-in.
- Change the