Commit faf9969e authored by Luke Duncalfe's avatar Luke Duncalfe

Filter shared groups autocomplete by permitted

Previously `Autocomplete::ProjectInvitedGroupsFinder` would return all
of a project's shared groups. It now filters the collection to only the
groups the user can see.

Changelog: security
EE: true
parent f29cabd6
...@@ -8,9 +8,7 @@ module Autocomplete ...@@ -8,9 +8,7 @@ module Autocomplete
# projects. # projects.
# #
# params - A Hash containing additional parameters to set. # params - A Hash containing additional parameters to set.
# # The supported parameters are those supported by `Autocomplete::ProjectFinder`.
# The supported parameters are those supported by
# `Autocomplete::ProjectFinder`.
def initialize(current_user, params = {}) def initialize(current_user, params = {})
@current_user = current_user @current_user = current_user
@params = params @params = params
...@@ -22,8 +20,21 @@ module Autocomplete ...@@ -22,8 +20,21 @@ module Autocomplete
.new(current_user, params) .new(current_user, params)
.execute .execute
project ? project.invited_groups : Group.none return Group.none unless project
invited_groups(project)
end end
# rubocop: enable CodeReuse/Finder # rubocop: enable CodeReuse/Finder
private
def invited_groups(project)
invited_groups = project.invited_groups
Group.from_union([
invited_groups.public_to_user(current_user),
invited_groups.for_authorized_group_members(current_user)
])
end
end end
end end
...@@ -3,12 +3,12 @@ ...@@ -3,12 +3,12 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe AutocompleteController do RSpec.describe AutocompleteController do
let(:project) { create(:project) } let_it_be(:user) { create(:user) }
let(:user) { project.owner } let_it_be(:project) { create(:project, namespace: user.namespace) }
context 'GET users' do context 'GET users' do
let!(:user2) { create(:user) } let_it_be(:user2) { create(:user) }
let!(:non_member) { create(:user) } let_it_be(:non_member) { create(:user) }
context 'project members' do context 'project members' do
before do before do
...@@ -58,12 +58,14 @@ RSpec.describe AutocompleteController do ...@@ -58,12 +58,14 @@ RSpec.describe AutocompleteController do
end end
context 'groups' do context 'groups' do
let(:matching_group) { create(:group) } let_it_be(:public_group) { create(:group, :public) }
let(:non_matching_group) { create(:group) } let_it_be(:authorized_private_group) { create(:group, :private) }
let(:user2) { create(:user) } let_it_be(:unauthorized_private_group) { create(:group, :private) }
let_it_be(:non_invited_group) { create(:group, :public) }
before do before_all do
project.invited_groups << matching_group authorized_private_group.add_guest(user)
project.invited_groups = [public_group, authorized_private_group, unauthorized_private_group]
end end
context "while fetching all groups belonging to a project" do context "while fetching all groups belonging to a project" do
...@@ -72,14 +74,17 @@ RSpec.describe AutocompleteController do ...@@ -72,14 +74,17 @@ RSpec.describe AutocompleteController do
get(:project_groups, params: { project_id: project.id }) get(:project_groups, params: { project_id: project.id })
end end
it 'returns a single group', :aggregate_failures do it 'returns groups invited to the project that the user can see' do
expect(json_response).to be_kind_of(Array) expect(json_response).to contain_exactly(
expect(json_response.size).to eq(1) a_hash_including("id" => authorized_private_group.id),
expect(json_response.first.values_at('id', 'name')).to eq [matching_group.id, matching_group.name] a_hash_including("id" => public_group.id)
)
end end
end end
context "while fetching all groups belonging to a project the current user cannot access" do context "while fetching all groups belonging to a project the current user cannot access" do
let(:user2) { create(:user) }
before do before do
sign_in(user2) sign_in(user2)
get(:project_groups, params: { project_id: project.id }) get(:project_groups, params: { project_id: project.id })
...@@ -91,7 +96,7 @@ RSpec.describe AutocompleteController do ...@@ -91,7 +96,7 @@ RSpec.describe AutocompleteController do
context "while fetching all groups belonging to an invalid project ID" do context "while fetching all groups belonging to an invalid project ID" do
before do before do
sign_in(user) sign_in(user)
get(:project_groups, params: { project_id: 'invalid' }) get(:project_groups, params: { project_id: non_existing_record_id })
end end
it { expect(response).to be_not_found } it { expect(response).to be_not_found }
...@@ -119,7 +124,7 @@ RSpec.describe AutocompleteController do ...@@ -119,7 +124,7 @@ RSpec.describe AutocompleteController do
end end
context 'as admin' do context 'as admin' do
let(:user) { create(:admin) } let_it_be(:user) { create(:admin) }
describe "while searching for a project by namespace" do describe "while searching for a project by namespace" do
let(:search) { group.path } let(:search) { group.path }
...@@ -171,7 +176,7 @@ RSpec.describe AutocompleteController do ...@@ -171,7 +176,7 @@ RSpec.describe AutocompleteController do
end end
context 'as admin' do context 'as admin' do
let(:user) { create(:admin) } let_it_be(:user) { create(:admin) }
describe "while searching for a namespace by group path" do describe "while searching for a namespace by group path" do
let(:search) { 'group' } let(:search) { 'group' }
......
...@@ -3,24 +3,43 @@ ...@@ -3,24 +3,43 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Autocomplete::ProjectInvitedGroupsFinder do RSpec.describe Autocomplete::ProjectInvitedGroupsFinder do
let(:user) { create(:user) }
describe '#execute' do describe '#execute' do
context 'without a project ID' do let_it_be(:user) { create(:user) }
it 'returns an empty relation' do let_it_be(:project) { create(:project, :private) }
expect(described_class.new(user).execute).to be_empty let_it_be(:public_group) { create(:group, :public) }
let_it_be(:authorized_private_group) { create(:group, :private) }
let_it_be(:unauthorized_private_group) { create(:group, :private) }
let_it_be(:non_invited_group) { create(:group, :public) }
before_all do
authorized_private_group.add_guest(user)
project.invited_groups = [authorized_private_group, unauthorized_private_group, public_group]
end end
it 'raises ActiveRecord::RecordNotFound if the project does not exist' do
finder = described_class.new(user, project_id: non_existing_record_id)
expect { finder.execute }.to raise_error(ActiveRecord::RecordNotFound)
end end
context 'with a project ID' do it 'raises ActiveRecord::RecordNotFound if the user is not authorized to see the project' do
it 'returns the groups invited to the project' do finder = described_class.new(user, project_id: project.id)
project = create(:project, :public)
group = create(:group)
create(:project_group_link, project: project, group: group) expect { finder.execute }.to raise_error(ActiveRecord::RecordNotFound)
end
it 'returns an empty relation without a project ID' do
expect(described_class.new(user).execute).to be_empty
end
context 'with a project the user is authorized to see' do
before_all do
project.add_guest(user)
end
it 'returns groups invited to the project that the user can see' do
expect(described_class.new(user, project_id: project.id).execute) expect(described_class.new(user, project_id: project.id).execute)
.to eq([group]) .to contain_exactly(authorized_private_group, public_group)
end end
end end
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment