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