summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelipe Artur <felipefac@gmail.com>2016-05-09 19:35:37 -0300
committerFelipe Artur <felipefac@gmail.com>2016-05-09 19:35:37 -0300
commite56e3cdc62f96541b9bd8b7814204e92f1909253 (patch)
treefc3872d2ba8c02ae552fc583cbdbb163d3340b20
parentae25c19ee5dcfae8ea977b2014657ecc6c3eaf3d (diff)
downloadgitlab-ce-e56e3cdc62f96541b9bd8b7814204e92f1909253.tar.gz
Fix api leaking notes when user is not authorized to read noteable
-rw-r--r--CHANGELOG1
-rw-r--r--lib/api/notes.rb31
-rw-r--r--spec/requests/api/notes_spec.rb19
3 files changed, 38 insertions, 13 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 63077523aaa..2c44944f66b 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -15,6 +15,7 @@ v 8.8.0 (unreleased)
- Bump mail_room to 0.7.0 to fix stuck IDLE connections
- Remove future dates from contribution calendar graph.
- Support e-mail notifications for comments on project snippets
+ - Fix API leak of notes of unauthorized issues, snippets and merge requests
- Use ActionDispatch Remote IP for Akismet checking
- Fix error when visiting commit builds page before build was updated
- Add 'l' shortcut to open Label dropdown on issuables and 'i' to create new issue on a project
diff --git a/lib/api/notes.rb b/lib/api/notes.rb
index 71a53e6f0d6..4ac08a3e8c4 100644
--- a/lib/api/notes.rb
+++ b/lib/api/notes.rb
@@ -20,19 +20,24 @@ module API
# GET /projects/:id/snippets/:noteable_id/notes
get ":id/#{noteables_str}/:#{noteable_id_str}/notes" do
@noteable = user_project.send(:"#{noteables_str}").find(params[:"#{noteable_id_str}"])
-
- # We exclude notes that are cross-references and that cannot be viewed
- # by the current user. By doing this exclusion at this level and not
- # at the DB query level (which we cannot in that case), the current
- # page can have less elements than :per_page even if
- # there's more than one page.
- notes =
- # paginate() only works with a relation. This could lead to a
- # mismatch between the pagination headers info and the actual notes
- # array returned, but this is really a edge-case.
- paginate(@noteable.notes).
- reject { |n| n.cross_reference_not_visible_for?(current_user) }
- present notes, with: Entities::Note
+ read_ability_name = "read_#{@noteable.class.to_s.underscore.downcase}".to_sym
+
+ if can?(current_user, read_ability_name, @noteable)
+ # We exclude notes that are cross-references and that cannot be viewed
+ # by the current user. By doing this exclusion at this level and not
+ # at the DB query level (which we cannot in that case), the current
+ # page can have less elements than :per_page even if
+ # there's more than one page.
+ notes =
+ # paginate() only works with a relation. This could lead to a
+ # mismatch between the pagination headers info and the actual notes
+ # array returned, but this is really a edge-case.
+ paginate(@noteable.notes).
+ reject { |n| n.cross_reference_not_visible_for?(current_user) }
+ present notes, with: Entities::Note
+ else
+ render_api_error!("Not found.", 404)
+ end
end
# Get a single +noteable+ note
diff --git a/spec/requests/api/notes_spec.rb b/spec/requests/api/notes_spec.rb
index 49091fc0f49..f5b31be1ba3 100644
--- a/spec/requests/api/notes_spec.rb
+++ b/spec/requests/api/notes_spec.rb
@@ -57,6 +57,15 @@ describe API::API, api: true do
expect(json_response).to be_empty
end
+ context "and issue is confidential" do
+ before { ext_issue.update_attributes(confidential: true) }
+
+ it "returns 404" do
+ get api("/projects/#{ext_proj.id}/issues/#{ext_issue.id}/notes", user)
+ expect(response.status).to eq(404)
+ end
+ end
+
context "and current user can view the note" do
it "should return an empty array" do
get api("/projects/#{ext_proj.id}/issues/#{ext_issue.id}/notes", private_user)
@@ -80,6 +89,11 @@ describe API::API, api: true do
get api("/projects/#{project.id}/snippets/42/notes", user)
expect(response.status).to eq(404)
end
+
+ it "returns 404 when not authorized" do
+ get api("/projects/#{project.id}/snippets/#{snippet.id}/notes", private_user)
+ expect(response.status).to eq(404)
+ end
end
context "when noteable is a Merge Request" do
@@ -94,6 +108,11 @@ describe API::API, api: true do
get api("/projects/#{project.id}/merge_requests/4444/notes", user)
expect(response.status).to eq(404)
end
+
+ it "returns 404 when not authorized" do
+ get api("/projects/#{project.id}/merge_requests/4444/notes", private_user)
+ expect(response.status).to eq(404)
+ end
end
end