Skip to content

`User#authorized_groups` does not return every group the user is authorized to see

If we take a closer look at how User#authorized_groups is implemented we can see that it only returns groups where the user has direct access, or one of the user projects belongs to a certain group.

The behavior should instead be:

  • User#authorized_groups returns all expanded groups
    • For a sub-group, it will return its parent/s and child groups

This can be done by changing the implementation to make use of the Gitlab::GroupHierarchy#all_groups method which expands all groups the user has access to. This method is already being used by GroupsFinder.

We could change the User#authorized_groups implementation to something like the following:

def authorized_groups
  union = Gitlab::SQL::Union
      .new([groups.select(:id), authorized_projects.select(:namespace_id)])
  groups_for_ancestors = Group.where("namespaces.id IN (#{union.to_sql})")
  groups_for_descendants = groups

  Gitlab::GroupHierarchy.new(groups_for_ancestors, groups_for_descendants).all_groups
end

There is one caveat though, this approach is extremely inefficient (EXPLAIN_authorized_groups__1_.txt)

Based on a previous discussion with @DouweM and @yorickpeterse, we previously had a similar problem with the authorized projects, which we solved by making an intermediate table that holds the authorized_projects for a user, maybe we could do something like this for the groups as well?