Skip to content

API endpoint to allow enterprise group Owners to delete enterprise users

What does this MR do and why?

Implements #520825 (closed)

Adds a DELETE :id/enterprise_users/:user_id endpoint to the Group enterprise users API.

The endpoint:

  • Allows the owner of an enterprise group to delete enterprise users in their group
  • Supports soft and hard deletion
  • Re-uses the existing User#delete_async method, which relies on DeleteUserWorker, so deletion logic has parity with regular user deletion

The endpoint is very similar to the logic in Admin::UsersController#destroy, with different authorization behaviour since this endpoint is EE-specific.

To achieve this, I added a new condition :can_delete_enterprise_user to EE::UserPolicy, and implement a new rule that gives users meeting that condition the :destroy_user ability.

Considerations

  • Since this operation is destructive I considered whether we'd want to release it behind a feature flag. I consulted "When to use feature flags" which explicitly mentions you may not need a flag for a new API endpoint.

    • The scenario I'd worry most about is the endpoint being abused to delete users inappropriately. However since the endpoint is restricted to Enterprise group owners, this seems very unlikely. In case a rogue group owner were able to delete users inappropriately, and we needed to restrict their ability before we could ship a revert, we could in theory modify the rogue account's permissions.
  • I believe we need a changelog entry for this change

  • I believe we also need to update documentation for this change, specifically the Group enterprise users API page.

References

Issue: #520825 (closed)

Screenshots or screen recordings

API-only change.

How to set up and validate locally

Set up a group with users

I recommend setting up two groups: one you can use to test successful deletion, and another you can use to test unsuccessful deletion.

  1. Follow these steps to ensure your GDK instance simulates SaaS
  2. Log in to your instance as root
  3. Create a few new users (Admin --> Users --> New user) a. One user will be the administrator of your enterprise group. Edit their account and give them a password, so they can log in to your instance.
  4. Create a group named Enterprise group (Admin --> Groups --> New group)
  5. Visit the admin page for the new group and go to user management (Groups --> --> Manage Access)
  6. Invite your group admin to be Owner of the group (Invite members --> choose your admin user --> give them Owner)
  7. Either invite the other users as developers as root, or log in as your admin user and invite them that way.
  8. As root, remove yourself as owner of the group.
  9. You now have a group with 1 owner user and 2 developer users.

Claim enterprise users

  1. Get a Rails console gdk rails c
  2. For each of your non-owner users, set their enterprise_group_id to "claim" them as EE users:
group = Group.find_by(path: 'enterprise-group')
[<username1>, <username2>].each { |name| User.find_by(username: name).user_detail.update!(enterprise_group_id: group.id) }

Test the API call

  1. Log in as your enterprise group owner
  2. Generate a Personal Access Token, with api scope at e.g. https://gdk.test:3443/-/user_settings/personal_access_tokens (User icon --> Edit profile --> Access Tokens a. Note the access token before you navigate away from this page
  3. Grab a shell prompt
  4. Set variables to set up your API call:
TOKEN=<your Personal Access Token>
GROUP_ID=<your group id>
USER_ID=<ID of the user to delete>
  1. Send HTTP request with curl:
> curl -X DELETE \
--header "PRIVATE-TOKEN: ${TOKEN}" \
"https://gdk.test:3443/api/v4/groups/${GROUP_ID}/enterprise_users/${USER_ID}"
  1. Observe blank response in terminal (good -- the endpoint returns 204 OK
  2. Grab a Rails console gdk rails c
  3. Verify the user was queued up for deletion
user_1 = User.find_by(username: <user1 username>)
ghost_migration = Users::GhostUserMigration.find_by(user_id: user_1.id)
  1. Observe the GhostUserMigration exists and hard_delete: false.
  2. Try the same API request for user 2, but try a hard delete. Back at the shell prompt:
> USER_ID=<user 2 ID>
> curl -X DELETE \
--header "PRIVATE-TOKEN: ${TOKEN}" \
"https://gdk.test:3443/api/v4/groups/${GROUP_ID}/enterprise_users/${USER_ID}?hard_delete=true"
  1. Verify in a Rails console:
user_2 = User.find_by(username: <user2 username>)
ghost_migration = Users::GhostUserMigration.find_by(user_id: user_2.id)
  1. Observe the GhostUserMigration exists, and hard_delete: true

Test the error path

  1. I'd recommend testing out the unhappy path for this as well. One way to do this is:
  2. Create another user and invite them to the existing enterprise group
  3. Claim the user as an enterprise user via Rails console
  4. Create a new enterprise group
  5. Create a new user who will be owner of the new enterprise group, and invite them to be owner of the group
  6. Remove yourself from the group
  7. Log in as the new enterprise group's owner
  8. Create a new Personal Access Token
  9. Set up the new API call:
TOKEN=<new enterprise group owner's PAT>
USER_ID=<user you just added to the OLD enterprise group>
  1. Make the API call again
  2. Observe the response {"message":"404 Group Not Found"} and the user was not deleted

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 Jason Knabl

Merge request reports

Loading