Commit 2563bb4c authored by Rémy Coutable's avatar Rémy Coutable

Merge branch '40855_remove_authentication_in_readonly_issue_api' into 'master'

Remove authentication for readonly endpoints in issues API

Closes #40855

See merge request gitlab-org/gitlab-ce!18638
parents 984e0f1a 789eb36c
---
title: made listing and showing public issue apis available without authentication
merge_request: 18638
author: haseebeqx
type: changed
...@@ -2,7 +2,7 @@ module API ...@@ -2,7 +2,7 @@ module API
class Issues < Grape::API class Issues < Grape::API
include PaginationParams include PaginationParams
before { authenticate! } before { authenticate_non_get! }
helpers ::Gitlab::IssuableMetadata helpers ::Gitlab::IssuableMetadata
...@@ -70,6 +70,7 @@ module API ...@@ -70,6 +70,7 @@ module API
desc: 'Return issues for the given scope: `created-by-me`, `assigned-to-me` or `all`' desc: 'Return issues for the given scope: `created-by-me`, `assigned-to-me` or `all`'
end end
get do get do
authenticate! unless params[:scope] == 'all'
issues = paginate(find_issues) issues = paginate(find_issues)
options = { options = {
......
...@@ -64,12 +64,32 @@ describe API::Issues do ...@@ -64,12 +64,32 @@ describe API::Issues do
describe "GET /issues" do describe "GET /issues" do
context "when unauthenticated" do context "when unauthenticated" do
it "returns authentication error" do it "returns an array of all issues" do
get api("/issues"), scope: 'all'
expect(response).to have_http_status(200)
expect(json_response).to be_an Array
end
it "returns authentication error without any scope" do
get api("/issues") get api("/issues")
expect(response).to have_gitlab_http_status(401) expect(response).to have_http_status(401)
end
it "returns authentication error when scope is assigned-to-me" do
get api("/issues"), scope: 'assigned-to-me'
expect(response).to have_http_status(401)
end
it "returns authentication error when scope is created-by-me" do
get api("/issues"), scope: 'created-by-me'
expect(response).to have_http_status(401)
end end
end end
context "when authenticated" do context "when authenticated" do
let(:first_issue) { json_response.first } let(:first_issue) { json_response.first }
...@@ -379,9 +399,6 @@ describe API::Issues do ...@@ -379,9 +399,6 @@ describe API::Issues do
end end
let!(:group_note) { create(:note_on_issue, author: user, project: group_project, noteable: group_issue) } let!(:group_note) { create(:note_on_issue, author: user, project: group_project, noteable: group_issue) }
before do
group_project.add_reporter(user)
end
let(:base_url) { "/groups/#{group.id}/issues" } let(:base_url) { "/groups/#{group.id}/issues" }
context 'when group has subgroups', :nested_groups do context 'when group has subgroups', :nested_groups do
...@@ -408,178 +425,201 @@ describe API::Issues do ...@@ -408,178 +425,201 @@ describe API::Issues do
end end
end end
it 'returns all group issues (including opened and closed)' do context 'when user is unauthenticated' do
get api(base_url, admin) it 'lists all issues in public projects' do
get api(base_url)
expect_paginated_array_response(size: 3) expect_paginated_array_response(size: 2)
end
end end
it 'returns group issues without confidential issues for non project members' do context 'when user is a group member' do
get api("#{base_url}?state=opened", non_member) before do
group_project.add_reporter(user)
end
expect_paginated_array_response(size: 1) it 'returns all group issues (including opened and closed)' do
expect(json_response.first['title']).to eq(group_issue.title) get api(base_url, admin)
end
it 'returns group confidential issues for author' do expect_paginated_array_response(size: 3)
get api("#{base_url}?state=opened", author) end
expect_paginated_array_response(size: 2) it 'returns group issues without confidential issues for non project members' do
end get api("#{base_url}?state=opened", non_member)
it 'returns group confidential issues for assignee' do expect_paginated_array_response(size: 1)
get api("#{base_url}?state=opened", assignee) expect(json_response.first['title']).to eq(group_issue.title)
end
expect_paginated_array_response(size: 2) it 'returns group confidential issues for author' do
end get api("#{base_url}?state=opened", author)
it 'returns group issues with confidential issues for project members' do expect_paginated_array_response(size: 2)
get api("#{base_url}?state=opened", user) end
expect_paginated_array_response(size: 2) it 'returns group confidential issues for assignee' do
end get api("#{base_url}?state=opened", assignee)
it 'returns group confidential issues for admin' do expect_paginated_array_response(size: 2)
get api("#{base_url}?state=opened", admin) end
expect_paginated_array_response(size: 2) it 'returns group issues with confidential issues for project members' do
end get api("#{base_url}?state=opened", user)
it 'returns an array of labeled group issues' do expect_paginated_array_response(size: 2)
get api("#{base_url}?labels=#{group_label.title}", user) end
expect_paginated_array_response(size: 1) it 'returns group confidential issues for admin' do
expect(json_response.first['labels']).to eq([group_label.title]) get api("#{base_url}?state=opened", admin)
end
it 'returns an array of labeled group issues where all labels match' do expect_paginated_array_response(size: 2)
get api("#{base_url}?labels=#{group_label.title},foo,bar", user) end
expect_paginated_array_response(size: 0) it 'returns an array of labeled group issues' do
end get api("#{base_url}?labels=#{group_label.title}", user)
it 'returns issues matching given search string for title' do expect_paginated_array_response(size: 1)
get api("#{base_url}?search=#{group_issue.title}", user) expect(json_response.first['labels']).to eq([group_label.title])
end
expect_paginated_array_response(size: 1) it 'returns an array of labeled group issues where all labels match' do
expect(json_response.first['id']).to eq(group_issue.id) get api("#{base_url}?labels=#{group_label.title},foo,bar", user)
end
it 'returns issues matching given search string for description' do expect_paginated_array_response(size: 0)
get api("#{base_url}?search=#{group_issue.description}", user) end
expect_paginated_array_response(size: 1) it 'returns issues matching given search string for title' do
expect(json_response.first['id']).to eq(group_issue.id) get api("#{base_url}?search=#{group_issue.title}", user)
end
it 'returns an array of labeled issues when all labels matches' do expect_paginated_array_response(size: 1)
label_b = create(:label, title: 'foo', project: group_project) expect(json_response.first['id']).to eq(group_issue.id)
label_c = create(:label, title: 'bar', project: group_project) end
create(:label_link, label: label_b, target: group_issue) it 'returns issues matching given search string for description' do
create(:label_link, label: label_c, target: group_issue) get api("#{base_url}?search=#{group_issue.description}", user)
get api("#{base_url}", user), labels: "#{group_label.title},#{label_b.title},#{label_c.title}" expect_paginated_array_response(size: 1)
expect(json_response.first['id']).to eq(group_issue.id)
end
expect_paginated_array_response(size: 1) it 'returns an array of labeled issues when all labels matches' do
expect(json_response.first['labels']).to eq([label_c.title, label_b.title, group_label.title]) label_b = create(:label, title: 'foo', project: group_project)
end label_c = create(:label, title: 'bar', project: group_project)
it 'returns an array of issues found by iids' do create(:label_link, label: label_b, target: group_issue)
get api(base_url, user), iids: [group_issue.iid] create(:label_link, label: label_c, target: group_issue)
expect_paginated_array_response(size: 1) get api("#{base_url}", user), labels: "#{group_label.title},#{label_b.title},#{label_c.title}"
expect(json_response.first['id']).to eq(group_issue.id)
end
it 'returns an empty array if iid does not exist' do expect_paginated_array_response(size: 1)
get api(base_url, user), iids: [99999] expect(json_response.first['labels']).to eq([label_c.title, label_b.title, group_label.title])
end
expect_paginated_array_response(size: 0) it 'returns an array of issues found by iids' do
end get api(base_url, user), iids: [group_issue.iid]
it 'returns an empty array if no group issue matches labels' do expect_paginated_array_response(size: 1)
get api("#{base_url}?labels=foo,bar", user) expect(json_response.first['id']).to eq(group_issue.id)
end
expect_paginated_array_response(size: 0) it 'returns an empty array if iid does not exist' do
end get api(base_url, user), iids: [99999]
it 'returns an empty array if no issue matches milestone' do expect_paginated_array_response(size: 0)
get api("#{base_url}?milestone=#{group_empty_milestone.title}", user) end
expect_paginated_array_response(size: 0) it 'returns an empty array if no group issue matches labels' do
end get api("#{base_url}?labels=foo,bar", user)
it 'returns an empty array if milestone does not exist' do expect_paginated_array_response(size: 0)
get api("#{base_url}?milestone=foo", user) end
expect_paginated_array_response(size: 0) it 'returns an empty array if no issue matches milestone' do
end get api("#{base_url}?milestone=#{group_empty_milestone.title}", user)
it 'returns an array of issues in given milestone' do expect_paginated_array_response(size: 0)
get api("#{base_url}?state=opened&milestone=#{group_milestone.title}", user) end
expect_paginated_array_response(size: 1) it 'returns an empty array if milestone does not exist' do
expect(json_response.first['id']).to eq(group_issue.id) get api("#{base_url}?milestone=foo", user)
end
it 'returns an array of issues matching state in milestone' do expect_paginated_array_response(size: 0)
get api("#{base_url}?milestone=#{group_milestone.title}"\ end
'&state=closed', user)
expect_paginated_array_response(size: 1) it 'returns an array of issues in given milestone' do
expect(json_response.first['id']).to eq(group_closed_issue.id) get api("#{base_url}?state=opened&milestone=#{group_milestone.title}", user)
end
it 'returns an array of issues with no milestone' do expect_paginated_array_response(size: 1)
get api("#{base_url}?milestone=#{no_milestone_title}", user) expect(json_response.first['id']).to eq(group_issue.id)
end
expect(response).to have_gitlab_http_status(200) it 'returns an array of issues matching state in milestone' do
get api("#{base_url}?milestone=#{group_milestone.title}"\
'&state=closed', user)
expect_paginated_array_response(size: 1) expect_paginated_array_response(size: 1)
expect(json_response.first['id']).to eq(group_confidential_issue.id) expect(json_response.first['id']).to eq(group_closed_issue.id)
end end
it 'sorts by created_at descending by default' do it 'returns an array of issues with no milestone' do
get api(base_url, user) get api("#{base_url}?milestone=#{no_milestone_title}", user)
response_dates = json_response.map { |issue| issue['created_at'] } expect(response).to have_gitlab_http_status(200)
expect_paginated_array_response(size: 3) expect_paginated_array_response(size: 1)
expect(response_dates).to eq(response_dates.sort.reverse) expect(json_response.first['id']).to eq(group_confidential_issue.id)
end end
it 'sorts ascending when requested' do it 'sorts by created_at descending by default' do
get api("#{base_url}?sort=asc", user) get api(base_url, user)
response_dates = json_response.map { |issue| issue['created_at'] } response_dates = json_response.map { |issue| issue['created_at'] }
expect_paginated_array_response(size: 3) expect_paginated_array_response(size: 3)
expect(response_dates).to eq(response_dates.sort) expect(response_dates).to eq(response_dates.sort.reverse)
end end
it 'sorts by updated_at descending when requested' do it 'sorts ascending when requested' do
get api("#{base_url}?order_by=updated_at", user) get api("#{base_url}?sort=asc", user)
response_dates = json_response.map { |issue| issue['updated_at'] } response_dates = json_response.map { |issue| issue['created_at'] }
expect_paginated_array_response(size: 3) expect_paginated_array_response(size: 3)
expect(response_dates).to eq(response_dates.sort.reverse) expect(response_dates).to eq(response_dates.sort)
end end
it 'sorts by updated_at ascending when requested' do it 'sorts by updated_at descending when requested' do
get api("#{base_url}?order_by=updated_at&sort=asc", user) get api("#{base_url}?order_by=updated_at", user)
response_dates = json_response.map { |issue| issue['updated_at'] } response_dates = json_response.map { |issue| issue['updated_at'] }
expect_paginated_array_response(size: 3) expect_paginated_array_response(size: 3)
expect(response_dates).to eq(response_dates.sort) expect(response_dates).to eq(response_dates.sort.reverse)
end
it 'sorts by updated_at ascending when requested' do
get api("#{base_url}?order_by=updated_at&sort=asc", user)
response_dates = json_response.map { |issue| issue['updated_at'] }
expect_paginated_array_response(size: 3)
expect(response_dates).to eq(response_dates.sort)
end
end end
end end
describe "GET /projects/:id/issues" do describe "GET /projects/:id/issues" do
let(:base_url) { "/projects/#{project.id}" } let(:base_url) { "/projects/#{project.id}" }
context 'when unauthenticated' do
it 'returns public project issues' do
get api("/projects/#{project.id}/issues")
expect_paginated_array_response(size: 2)
expect(json_response.first['title']).to eq(issue.title)
end
end
it 'avoids N+1 queries' do it 'avoids N+1 queries' do
control_count = ActiveRecord::QueryRecorder.new do control_count = ActiveRecord::QueryRecorder.new do
get api("/projects/#{project.id}/issues", user) get api("/projects/#{project.id}/issues", user)
...@@ -789,6 +829,14 @@ describe API::Issues do ...@@ -789,6 +829,14 @@ describe API::Issues do
end end
describe "GET /projects/:id/issues/:issue_iid" do describe "GET /projects/:id/issues/:issue_iid" do
context 'when unauthenticated' do
it 'returns public issues' do
get api("/projects/#{project.id}/issues/#{issue.iid}")
expect(response).to have_gitlab_http_status(200)
end
end
it 'exposes known attributes' do it 'exposes known attributes' do
get api("/projects/#{project.id}/issues/#{issue.iid}", user) get api("/projects/#{project.id}/issues/#{issue.iid}", user)
...@@ -1581,6 +1629,14 @@ describe API::Issues do ...@@ -1581,6 +1629,14 @@ describe API::Issues do
create(:merge_requests_closing_issues, issue: issue, merge_request: merge_request) create(:merge_requests_closing_issues, issue: issue, merge_request: merge_request)
end end
context 'when unauthenticated' do
it 'return public project issues' do
get api("/projects/#{project.id}/issues/#{issue.iid}/closed_by")
expect_paginated_array_response(size: 1)
end
end
it 'returns merge requests that will close issue on merge' do it 'returns merge requests that will close issue on merge' do
get api("/projects/#{project.id}/issues/#{issue.iid}/closed_by", user) get api("/projects/#{project.id}/issues/#{issue.iid}/closed_by", user)
...@@ -1605,6 +1661,14 @@ describe API::Issues do ...@@ -1605,6 +1661,14 @@ describe API::Issues do
describe "GET /projects/:id/issues/:issue_iid/user_agent_detail" do describe "GET /projects/:id/issues/:issue_iid/user_agent_detail" do
let!(:user_agent_detail) { create(:user_agent_detail, subject: issue) } let!(:user_agent_detail) { create(:user_agent_detail, subject: issue) }
context 'when unauthenticated' do
it "returns unautorized" do
get api("/projects/#{project.id}/issues/#{issue.iid}/user_agent_detail")
expect(response).to have_gitlab_http_status(401)
end
end
it 'exposes known attributes' do it 'exposes known attributes' do
get api("/projects/#{project.id}/issues/#{issue.iid}/user_agent_detail", admin) get api("/projects/#{project.id}/issues/#{issue.iid}/user_agent_detail", admin)
......
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