Update PATCH /Groups/:id SCIM endpoint to use worker

This is part of Implement `PUT /Groups/:id` and `PATCH /Groups/... (#509428 - closed).

This depends on Add SyncScimGroupMembersWorker for SCIM group m... (!188566 - merged).

What does this MR do and why?

This MR adds support for the "remove" operation to the PATCH /Groups/:id SCIM endpoint for self-managed instances and updates both "add" and "remove" operations to be processed asynchronously. This allows identity providers (like Okta and Microsoft Entra ID) to efficiently manage group memberships as part of SCIM group synchronization.

Key facts:

  1. Adds "remove" operation support to the PATCH endpoint
  2. Makes operations asynchronous by leveraging the Authn::SyncScimGroupMembersWorker
  3. Refactors the GroupSyncPatchService to delegate to the worker

The feature remains behind the same feature flag (self_managed_scim_group_sync) as the previous implementation. The FF is default disabled.

References

How to set up and validate locally

  1. Make sure you have SAML enabled on your GDK.

  2. Enter the Rails console:

gdk rails c
  1. Create test SAML group links and user identities:
# Create a group and SAML link with SCIM ID
group = Group.first # or create a specific test group
saml_group_link = SamlGroupLink.create!(
  group: group,
  saml_group_name: "engineering",
  access_level: Gitlab::Access::DEVELOPER,
  scim_group_uid: SecureRandom.uuid
)
puts saml_group_link.scim_group_uid # Copy this UUID for the curl command

# Create a user with SCIM identity
user = User.first # or create a specific test user
identity = ScimIdentity.create!(
  user: user,
  extern_uid: "user-scim-id",
  active: true
)
puts identity.extern_uid # Copy this ID for the request payload

# Add the user to the group
group.add_member(user, Gitlab::Access::DEVELOPER)
  1. Enable the required feature flag:
Feature.enable(:self_managed_scim_group_sync)
  1. Create a SCIM access token if needed:
token = ScimOauthAccessToken.create!
puts token.token  # Copy this token for the curl command
  1. Make the API request to remove a user from the group:
curl --location --request PATCH 'http://localhost:3000/api/scim/v2/application/Groups/YOUR_GROUP_UUID' \
--header 'Content-Type: application/json' \
--header 'Accept: application/scim+json' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--data-raw '{
  "schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
  "Operations": [
    {
      "op": "Remove",
      "path": "members",
      "value": [
        {
          "value": "user-scim-id"
        }
      ]
    }
  ]
}'
  1. Verify the worker processes the removal:
# In Rails console
Sidekiq::Queue.new('authn_sync_scim_group_members').size  # Should be 1 if job is queued
# Or check Sidekiq dashboard

Expected Results

  • API call should return 204 No Content status code immediately
  • The Sidekiq job should be enqueued for processing
  • After job execution, the user should be removed from the specified group
  • Multiple SAML group links with the same SCIM ID should all be processed

MR acceptance checklist

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

Edited by Paulo Barros

Merge request reports

Loading