Commit 03dba1fd authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Merge pull request #5344 from amacarthur/thread-variable-fix

Fixing unsafe use of Thread.current variable :current_user
parents dad83166 aefe2e95
...@@ -2,7 +2,7 @@ class ApplicationController < ActionController::Base ...@@ -2,7 +2,7 @@ class ApplicationController < ActionController::Base
before_filter :authenticate_user! before_filter :authenticate_user!
before_filter :reject_blocked! before_filter :reject_blocked!
before_filter :check_password_expiration before_filter :check_password_expiration
before_filter :set_current_user_for_thread around_filter :set_current_user_for_thread
before_filter :add_abilities before_filter :add_abilities
before_filter :dev_tools if Rails.env == 'development' before_filter :dev_tools if Rails.env == 'development'
before_filter :default_headers before_filter :default_headers
...@@ -50,6 +50,11 @@ class ApplicationController < ActionController::Base ...@@ -50,6 +50,11 @@ class ApplicationController < ActionController::Base
def set_current_user_for_thread def set_current_user_for_thread
Thread.current[:current_user] = current_user Thread.current[:current_user] = current_user
begin
yield
ensure
Thread.current[:current_user] = nil
end
end end
def abilities def abilities
......
...@@ -11,17 +11,22 @@ Gitlab::Seeder.quiet do ...@@ -11,17 +11,22 @@ Gitlab::Seeder.quiet do
next unless user next unless user
user_id = user.id user_id = user.id
Thread.current[:current_user] = user
Issue.seed(:id, [{ begin
id: i, Thread.current[:current_user] = user
project_id: project.id,
author_id: user_id, Issue.seed(:id, [{
assignee_id: user_id, id: i,
state: ['opened', 'closed'].sample, project_id: project.id,
milestone: project.milestones.sample, author_id: user_id,
title: Faker::Lorem.sentence(6) assignee_id: user_id,
}]) state: ['opened', 'closed'].sample,
milestone: project.milestones.sample,
title: Faker::Lorem.sentence(6)
}])
ensure
Thread.current[:current_user] = nil
end
print('.') print('.')
end end
......
...@@ -17,19 +17,23 @@ Gitlab::Seeder.quiet do ...@@ -17,19 +17,23 @@ Gitlab::Seeder.quiet do
next if branches.uniq.size < 2 next if branches.uniq.size < 2
user_id = user.id user_id = user.id
Thread.current[:current_user] = user begin
Thread.current[:current_user] = user
MergeRequest.seed(:id, [{
id: i, MergeRequest.seed(:id, [{
source_branch: branches.first, id: i,
target_branch: branches.last, source_branch: branches.first,
source_project_id: project.id, target_branch: branches.last,
target_project_id: project.id, source_project_id: project.id,
author_id: user_id, target_project_id: project.id,
assignee_id: user_id, author_id: user_id,
milestone: project.milestones.sample, assignee_id: user_id,
title: Faker::Lorem.sentence(6) milestone: project.milestones.sample,
}]) title: Faker::Lorem.sentence(6)
}])
ensure
Thread.current[:current_user] = nil
end
print('.') print('.')
end end
end end
......
...@@ -51,4 +51,6 @@ Spinach.hooks.before_run do ...@@ -51,4 +51,6 @@ Spinach.hooks.before_run do
RSpec::Mocks::setup self RSpec::Mocks::setup self
include FactoryGirl::Syntax::Methods include FactoryGirl::Syntax::Methods
MergeRequestObserver.any_instance.stub(current_user: create(:user))
end end
...@@ -27,6 +27,15 @@ module API ...@@ -27,6 +27,15 @@ module API
end end
end end
def set_current_user_for_thread
Thread.current[:current_user] = current_user
begin
yield
ensure
Thread.current[:current_user] = nil
end
end
def user_project def user_project
@project ||= find_project(params[:id]) @project ||= find_project(params[:id])
@project || not_found! @project || not_found!
......
...@@ -2,7 +2,6 @@ module API ...@@ -2,7 +2,6 @@ module API
# Issues API # Issues API
class Issues < Grape::API class Issues < Grape::API
before { authenticate! } before { authenticate! }
before { Thread.current[:current_user] = current_user }
resource :issues do resource :issues do
# Get currently authenticated user's issues # Get currently authenticated user's issues
...@@ -49,15 +48,17 @@ module API ...@@ -49,15 +48,17 @@ module API
# Example Request: # Example Request:
# POST /projects/:id/issues # POST /projects/:id/issues
post ":id/issues" do post ":id/issues" do
required_attributes! [:title] set_current_user_for_thread do
attrs = attributes_for_keys [:title, :description, :assignee_id, :milestone_id] required_attributes! [:title]
attrs[:label_list] = params[:labels] if params[:labels].present? attrs = attributes_for_keys [:title, :description, :assignee_id, :milestone_id]
@issue = user_project.issues.new attrs attrs[:label_list] = params[:labels] if params[:labels].present?
@issue.author = current_user @issue = user_project.issues.new attrs
if @issue.save @issue.author = current_user
present @issue, with: Entities::Issue if @issue.save
else present @issue, with: Entities::Issue
not_found! else
not_found!
end
end end
end end
...@@ -75,16 +76,18 @@ module API ...@@ -75,16 +76,18 @@ module API
# Example Request: # Example Request:
# PUT /projects/:id/issues/:issue_id # PUT /projects/:id/issues/:issue_id
put ":id/issues/:issue_id" do put ":id/issues/:issue_id" do
@issue = user_project.issues.find(params[:issue_id]) set_current_user_for_thread do
authorize! :modify_issue, @issue @issue = user_project.issues.find(params[:issue_id])
authorize! :modify_issue, @issue
attrs = attributes_for_keys [:title, :description, :assignee_id, :milestone_id, :state_event] attrs = attributes_for_keys [:title, :description, :assignee_id, :milestone_id, :state_event]
attrs[:label_list] = params[:labels] if params[:labels].present? attrs[:label_list] = params[:labels] if params[:labels].present?
if @issue.update_attributes attrs if @issue.update_attributes attrs
present @issue, with: Entities::Issue present @issue, with: Entities::Issue
else else
not_found! not_found!
end
end end
end end
......
...@@ -2,7 +2,6 @@ module API ...@@ -2,7 +2,6 @@ module API
# MergeRequest API # MergeRequest API
class MergeRequests < Grape::API class MergeRequests < Grape::API
before { authenticate! } before { authenticate! }
before { Thread.current[:current_user] = current_user }
resource :projects do resource :projects do
helpers do helpers do
...@@ -70,28 +69,30 @@ module API ...@@ -70,28 +69,30 @@ module API
# POST /projects/:id/merge_requests # POST /projects/:id/merge_requests
# #
post ":id/merge_requests" do post ":id/merge_requests" do
authorize! :write_merge_request, user_project set_current_user_for_thread do
required_attributes! [:source_branch, :target_branch, :title] authorize! :write_merge_request, user_project
attrs = attributes_for_keys [:source_branch, :target_branch, :assignee_id, :title, :target_project_id] required_attributes! [:source_branch, :target_branch, :title]
merge_request = user_project.merge_requests.new(attrs) attrs = attributes_for_keys [:source_branch, :target_branch, :assignee_id, :title, :target_project_id]
merge_request.author = current_user merge_request = user_project.merge_requests.new(attrs)
merge_request.source_project = user_project merge_request.author = current_user
target_project_id = attrs[:target_project_id] merge_request.source_project = user_project
if not_fork?(target_project_id, user_project) target_project_id = attrs[:target_project_id]
merge_request.target_project = user_project if not_fork?(target_project_id, user_project)
else merge_request.target_project = user_project
if target_matches_fork(target_project_id,user_project)
merge_request.target_project = Project.find_by_id(attrs[:target_project_id])
else else
render_api_error!('(Bad Request) Specified target project that is not the source project, or the source fork of the project.', 400) if target_matches_fork(target_project_id,user_project)
merge_request.target_project = Project.find_by_id(attrs[:target_project_id])
else
render_api_error!('(Bad Request) Specified target project that is not the source project, or the source fork of the project.', 400)
end
end end
end
if merge_request.save if merge_request.save
merge_request.reload_code merge_request.reload_code
present merge_request, with: Entities::MergeRequest present merge_request, with: Entities::MergeRequest
else else
handle_merge_request_errors! merge_request.errors handle_merge_request_errors! merge_request.errors
end
end end
end end
...@@ -109,17 +110,19 @@ module API ...@@ -109,17 +110,19 @@ module API
# PUT /projects/:id/merge_request/:merge_request_id # PUT /projects/:id/merge_request/:merge_request_id
# #
put ":id/merge_request/:merge_request_id" do put ":id/merge_request/:merge_request_id" do
attrs = attributes_for_keys [:source_branch, :target_branch, :assignee_id, :title, :state_event] set_current_user_for_thread do
merge_request = user_project.merge_requests.find(params[:merge_request_id]) attrs = attributes_for_keys [:source_branch, :target_branch, :assignee_id, :title, :state_event]
merge_request = user_project.merge_requests.find(params[:merge_request_id])
authorize! :modify_merge_request, merge_request authorize! :modify_merge_request, merge_request
if merge_request.update_attributes attrs if merge_request.update_attributes attrs
merge_request.reload_code merge_request.reload_code
merge_request.mark_as_unchecked merge_request.mark_as_unchecked
present merge_request, with: Entities::MergeRequest present merge_request, with: Entities::MergeRequest
else else
handle_merge_request_errors! merge_request.errors handle_merge_request_errors! merge_request.errors
end
end end
end end
...@@ -133,16 +136,18 @@ module API ...@@ -133,16 +136,18 @@ module API
# POST /projects/:id/merge_request/:merge_request_id/comments # POST /projects/:id/merge_request/:merge_request_id/comments
# #
post ":id/merge_request/:merge_request_id/comments" do post ":id/merge_request/:merge_request_id/comments" do
required_attributes! [:note] set_current_user_for_thread do
required_attributes! [:note]
merge_request = user_project.merge_requests.find(params[:merge_request_id]) merge_request = user_project.merge_requests.find(params[:merge_request_id])
note = merge_request.notes.new(note: params[:note], project_id: user_project.id) note = merge_request.notes.new(note: params[:note], project_id: user_project.id)
note.author = current_user note.author = current_user
if note.save if note.save
present note, with: Entities::MRNote present note, with: Entities::MRNote
else else
not_found! not_found!
end
end end
end end
......
...@@ -40,15 +40,17 @@ module API ...@@ -40,15 +40,17 @@ module API
# Example Request: # Example Request:
# POST /projects/:id/milestones # POST /projects/:id/milestones
post ":id/milestones" do post ":id/milestones" do
authorize! :admin_milestone, user_project set_current_user_for_thread do
required_attributes! [:title] authorize! :admin_milestone, user_project
required_attributes! [:title]
attrs = attributes_for_keys [:title, :description, :due_date] attrs = attributes_for_keys [:title, :description, :due_date]
@milestone = user_project.milestones.new attrs @milestone = user_project.milestones.new attrs
if @milestone.save if @milestone.save
present @milestone, with: Entities::Milestone present @milestone, with: Entities::Milestone
else else
not_found! not_found!
end
end end
end end
...@@ -64,14 +66,16 @@ module API ...@@ -64,14 +66,16 @@ module API
# Example Request: # Example Request:
# PUT /projects/:id/milestones/:milestone_id # PUT /projects/:id/milestones/:milestone_id
put ":id/milestones/:milestone_id" do put ":id/milestones/:milestone_id" do
authorize! :admin_milestone, user_project set_current_user_for_thread do
authorize! :admin_milestone, user_project
@milestone = user_project.milestones.find(params[:milestone_id]) @milestone = user_project.milestones.find(params[:milestone_id])
attrs = attributes_for_keys [:title, :description, :due_date, :state_event] attrs = attributes_for_keys [:title, :description, :due_date, :state_event]
if @milestone.update_attributes attrs if @milestone.update_attributes attrs
present @milestone, with: Entities::Milestone present @milestone, with: Entities::Milestone
else else
not_found! not_found!
end
end end
end end
end end
......
...@@ -41,17 +41,19 @@ module API ...@@ -41,17 +41,19 @@ module API
# Example Request: # Example Request:
# POST /projects/:id/notes # POST /projects/:id/notes
post ":id/notes" do post ":id/notes" do
required_attributes! [:body] set_current_user_for_thread do
required_attributes! [:body]
@note = user_project.notes.new(note: params[:body]) @note = user_project.notes.new(note: params[:body])
@note.author = current_user @note.author = current_user
if @note.save if @note.save
present @note, with: Entities::Note present @note, with: Entities::Note
else else
# :note is exposed as :body, but :note is set on error # :note is exposed as :body, but :note is set on error
bad_request!(:note) if @note.errors[:note].any? bad_request!(:note) if @note.errors[:note].any?
not_found! not_found!
end
end end
end end
...@@ -97,17 +99,19 @@ module API ...@@ -97,17 +99,19 @@ module API
# POST /projects/:id/issues/:noteable_id/notes # POST /projects/:id/issues/:noteable_id/notes
# POST /projects/:id/snippets/:noteable_id/notes # POST /projects/:id/snippets/:noteable_id/notes
post ":id/#{noteables_str}/:#{noteable_id_str}/notes" do post ":id/#{noteables_str}/:#{noteable_id_str}/notes" do
required_attributes! [:body] set_current_user_for_thread do
required_attributes! [:body]
@noteable = user_project.send(:"#{noteables_str}").find(params[:"#{noteable_id_str}"]) @noteable = user_project.send(:"#{noteables_str}").find(params[:"#{noteable_id_str}"])
@note = @noteable.notes.new(note: params[:body]) @note = @noteable.notes.new(note: params[:body])
@note.author = current_user @note.author = current_user
@note.project = user_project @note.project = user_project
if @note.save if @note.save
present @note, with: Entities::Note present @note, with: Entities::Note
else else
not_found! not_found!
end
end end
end end
end end
......
...@@ -27,14 +27,8 @@ ...@@ -27,14 +27,8 @@
require 'spec_helper' require 'spec_helper'
describe Project do describe Project do
let(:user) { create(:user) } before { enable_observers }
after { disable_observers }
before do
enable_observers
Thread.current[:current_user] = user
end
after { disable_observers }
describe "Associations" do describe "Associations" do
it { should belong_to(:group) } it { should belong_to(:group) }
......
...@@ -100,4 +100,16 @@ describe API::API do ...@@ -100,4 +100,16 @@ describe API::API do
response.status.should == 405 response.status.should == 405
end end
end end
describe "PUT /projects/:id/issues/:issue_id to test observer on close" do
before { enable_observers }
after { disable_observers }
it "should create an activity event when an issue is closed" do
Event.should_receive(:create)
put api("/projects/#{project.id}/issues/#{issue.id}", user),
state_event: "close"
end
end
end end
...@@ -90,4 +90,16 @@ describe API::API do ...@@ -90,4 +90,16 @@ describe API::API do
json_response['state'].should == 'closed' json_response['state'].should == 'closed'
end end
end end
describe "PUT /projects/:id/milestones/:milestone_id to test observer on close" do
before { enable_observers }
after { disable_observers }
it "should create an activity event when an milestone is closed" do
Event.should_receive(:create)
put api("/projects/#{project.id}/milestones/#{milestone.id}", user),
state_event: 'close'
end
end
end end
...@@ -176,4 +176,16 @@ describe API::API do ...@@ -176,4 +176,16 @@ describe API::API do
end end
end end
end end
describe "POST /projects/:id/noteable/:noteable_id/notes to test observer on create" do
before { enable_observers }
after { disable_observers }
it "should create an activity event when an issue note is created" do
Event.should_receive(:create)
post api("/projects/#{project.id}/issues/#{issue.id}/notes", user), body: 'hi!'
end
end
end end
...@@ -84,6 +84,11 @@ module TestEnv ...@@ -84,6 +84,11 @@ module TestEnv
Repository.any_instance.stub( Repository.any_instance.stub(
size: 12.45 size: 12.45
) )
ActivityObserver.any_instance.stub(
current_user: double("current_user", id: 1)
)
end end
def clear_repo_dir(namespace, name) def clear_repo_dir(namespace, name)
......
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