Commit 23d37382 authored by Michael Kozono's avatar Michael Kozono

Refactor to let GitAccess errors bubble up

No external behavior change.

This allows `GitHttpController` to set the HTTP status based on the type of error. Alternatively, we could have added an attribute to GitAccessStatus, but this pattern seemed appropriate.
parent 957edb13
class Projects::GitHttpController < Projects::GitHttpClientController class Projects::GitHttpController < Projects::GitHttpClientController
include WorkhorseRequest include WorkhorseRequest
before_action :access_check
rescue_from Gitlab::GitAccess::UnauthorizedError, with: :render_403
rescue_from Gitlab::GitAccess::NotFoundError, with: :render_404
# GET /foo/bar.git/info/refs?service=git-upload-pack (git pull) # GET /foo/bar.git/info/refs?service=git-upload-pack (git pull)
# GET /foo/bar.git/info/refs?service=git-receive-pack (git push) # GET /foo/bar.git/info/refs?service=git-receive-pack (git push)
def info_refs def info_refs
if upload_pack? && upload_pack_allowed? log_user_activity if upload_pack?
log_user_activity
render_ok render_ok
elsif receive_pack? && receive_pack_allowed?
render_ok
else
render_denied
end
end end
# POST /foo/bar.git/git-upload-pack (git pull) # POST /foo/bar.git/git-upload-pack (git pull)
def git_upload_pack def git_upload_pack
if upload_pack? && upload_pack_allowed?
render_ok render_ok
else
render_denied
end
end end
# POST /foo/bar.git/git-receive-pack" (git push) # POST /foo/bar.git/git-receive-pack" (git push)
def git_receive_pack def git_receive_pack
if receive_pack? && receive_pack_allowed?
render_ok render_ok
else
render_denied
end
end end
private private
...@@ -43,10 +34,6 @@ class Projects::GitHttpController < Projects::GitHttpClientController ...@@ -43,10 +34,6 @@ class Projects::GitHttpController < Projects::GitHttpClientController
git_command == 'git-upload-pack' git_command == 'git-upload-pack'
end end
def receive_pack?
git_command == 'git-receive-pack'
end
def git_command def git_command
if action_name == 'info_refs' if action_name == 'info_refs'
params[:service] params[:service]
...@@ -60,16 +47,12 @@ class Projects::GitHttpController < Projects::GitHttpClientController ...@@ -60,16 +47,12 @@ class Projects::GitHttpController < Projects::GitHttpClientController
render json: Gitlab::Workhorse.git_http_ok(repository, wiki?, user, action_name) render json: Gitlab::Workhorse.git_http_ok(repository, wiki?, user, action_name)
end end
def render_denied def render_403(exception)
if access_check.message == Gitlab::GitAccess::ERROR_MESSAGES[:project_not_found] render plain: exception.message, status: :forbidden
render plain: access_check.message, status: :not_found
else
render plain: access_check.message, status: :forbidden
end
end end
def upload_pack_allowed? def render_404(exception)
access_check.allowed? render plain: exception.message, status: :not_found
end end
def access def access
...@@ -84,11 +67,7 @@ class Projects::GitHttpController < Projects::GitHttpClientController ...@@ -84,11 +67,7 @@ class Projects::GitHttpController < Projects::GitHttpClientController
def access_check def access_check
# Use the magic string '_any' to indicate we do not know what the # Use the magic string '_any' to indicate we do not know what the
# changes are. This is also what gitlab-shell does. # changes are. This is also what gitlab-shell does.
@access_check ||= access.check(git_command, '_any') access.check(git_command, '_any')
end
def receive_pack_allowed?
access_check.allowed?
end end
def access_klass def access_klass
......
...@@ -32,14 +32,17 @@ module API ...@@ -32,14 +32,17 @@ module API
actor.update_last_used_at if actor.is_a?(Key) actor.update_last_used_at if actor.is_a?(Key)
access_checker = wiki? ? Gitlab::GitAccessWiki : Gitlab::GitAccess access_checker_klass = wiki? ? Gitlab::GitAccessWiki : Gitlab::GitAccess
access_status = access_checker access_checker = access_checker_klass
.new(actor, project, protocol, authentication_abilities: ssh_authentication_abilities) .new(actor, project, protocol, authentication_abilities: ssh_authentication_abilities)
.check(params[:action], params[:changes])
begin
access_status = access_checker.check(params[:action], params[:changes])
response = { status: access_status.status, message: access_status.message } response = { status: access_status.status, message: access_status.message }
rescue Gitlab::GitAccess::UnauthorizedError, Gitlab::GitAccess::NotFoundError => e
return { status: false, message: e.message }
end
if access_status.status
log_user_activity(actor) log_user_activity(actor)
# Project id to pass between components that don't share/don't have # Project id to pass between components that don't share/don't have
...@@ -54,7 +57,6 @@ module API ...@@ -54,7 +57,6 @@ module API
else else
project.repository.path_to_repo project.repository.path_to_repo
end end
end
response response
end end
......
...@@ -33,20 +33,18 @@ module Gitlab ...@@ -33,20 +33,18 @@ module Gitlab
def exec def exec
return GitAccessStatus.new(true) if skip_authorization return GitAccessStatus.new(true) if skip_authorization
error = push_checks || branch_checks || tag_checks push_checks
branch_checks
tag_checks
if error
GitAccessStatus.new(false, error)
else
GitAccessStatus.new(true) GitAccessStatus.new(true)
end end
end
protected protected
def push_checks def push_checks
if user_access.cannot_do_action?(:push_code) if user_access.cannot_do_action?(:push_code)
ERROR_MESSAGES[:push_code] raise GitAccess::UnauthorizedError, ERROR_MESSAGES[:push_code]
end end
end end
...@@ -54,7 +52,7 @@ module Gitlab ...@@ -54,7 +52,7 @@ module Gitlab
return unless @branch_name return unless @branch_name
if deletion? && @branch_name == project.default_branch if deletion? && @branch_name == project.default_branch
return ERROR_MESSAGES[:delete_default_branch] raise GitAccess::UnauthorizedError, ERROR_MESSAGES[:delete_default_branch]
end end
protected_branch_checks protected_branch_checks
...@@ -64,7 +62,7 @@ module Gitlab ...@@ -64,7 +62,7 @@ module Gitlab
return unless ProtectedBranch.protected?(project, @branch_name) return unless ProtectedBranch.protected?(project, @branch_name)
if forced_push? if forced_push?
return ERROR_MESSAGES[:force_push_protected_branch] raise GitAccess::UnauthorizedError, ERROR_MESSAGES[:force_push_protected_branch]
end end
if deletion? if deletion?
...@@ -76,22 +74,22 @@ module Gitlab ...@@ -76,22 +74,22 @@ module Gitlab
def protected_branch_deletion_checks def protected_branch_deletion_checks
unless user_access.can_delete_branch?(@branch_name) unless user_access.can_delete_branch?(@branch_name)
return ERROR_MESSAGES[:non_master_delete_protected_branch] raise GitAccess::UnauthorizedError, ERROR_MESSAGES[:non_master_delete_protected_branch]
end end
unless protocol == 'web' unless protocol == 'web'
ERROR_MESSAGES[:non_web_delete_protected_branch] raise GitAccess::UnauthorizedError, ERROR_MESSAGES[:non_web_delete_protected_branch]
end end
end end
def protected_branch_push_checks def protected_branch_push_checks
if matching_merge_request? if matching_merge_request?
unless user_access.can_merge_to_branch?(@branch_name) || user_access.can_push_to_branch?(@branch_name) unless user_access.can_merge_to_branch?(@branch_name) || user_access.can_push_to_branch?(@branch_name)
ERROR_MESSAGES[:merge_protected_branch] raise GitAccess::UnauthorizedError, ERROR_MESSAGES[:merge_protected_branch]
end end
else else
unless user_access.can_push_to_branch?(@branch_name) unless user_access.can_push_to_branch?(@branch_name)
ERROR_MESSAGES[:push_protected_branch] raise GitAccess::UnauthorizedError, ERROR_MESSAGES[:push_protected_branch]
end end
end end
end end
...@@ -100,7 +98,7 @@ module Gitlab ...@@ -100,7 +98,7 @@ module Gitlab
return unless @tag_name return unless @tag_name
if tag_exists? && user_access.cannot_do_action?(:admin_project) if tag_exists? && user_access.cannot_do_action?(:admin_project)
return ERROR_MESSAGES[:change_existing_tags] raise GitAccess::UnauthorizedError, ERROR_MESSAGES[:change_existing_tags]
end end
protected_tag_checks protected_tag_checks
...@@ -109,11 +107,11 @@ module Gitlab ...@@ -109,11 +107,11 @@ module Gitlab
def protected_tag_checks def protected_tag_checks
return unless ProtectedTag.protected?(project, @tag_name) return unless ProtectedTag.protected?(project, @tag_name)
return ERROR_MESSAGES[:update_protected_tag] if update? raise(GitAccess::UnauthorizedError, ERROR_MESSAGES[:update_protected_tag]) if update?
return ERROR_MESSAGES[:delete_protected_tag] if deletion? raise(GitAccess::UnauthorizedError, ERROR_MESSAGES[:delete_protected_tag]) if deletion?
unless user_access.can_create_tag?(@tag_name) unless user_access.can_create_tag?(@tag_name)
return ERROR_MESSAGES[:create_protected_tag] raise GitAccess::UnauthorizedError, ERROR_MESSAGES[:create_protected_tag]
end end
end end
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
module Gitlab module Gitlab
class GitAccess class GitAccess
UnauthorizedError = Class.new(StandardError) UnauthorizedError = Class.new(StandardError)
NotFoundError = Class.new(StandardError)
ERROR_MESSAGES = { ERROR_MESSAGES = {
upload: 'You are not allowed to upload code for this project.', upload: 'You are not allowed to upload code for this project.',
...@@ -47,8 +48,6 @@ module Gitlab ...@@ -47,8 +48,6 @@ module Gitlab
end end
build_status_object(true) build_status_object(true)
rescue UnauthorizedError => ex
build_status_object(false, ex.message)
end end
def guest_can_download_code? def guest_can_download_code?
...@@ -90,7 +89,7 @@ module Gitlab ...@@ -90,7 +89,7 @@ module Gitlab
def check_project_accessibility! def check_project_accessibility!
if project.blank? || !can_read_project? if project.blank? || !can_read_project?
raise UnauthorizedError, ERROR_MESSAGES[:project_not_found] raise NotFoundError, ERROR_MESSAGES[:project_not_found]
end end
end end
...@@ -234,8 +233,8 @@ module Gitlab ...@@ -234,8 +233,8 @@ module Gitlab
end end
end end
def build_status_object(status, message = '') def build_status_object(status)
Gitlab::GitAccessStatus.new(status, message) Gitlab::GitAccessStatus.new(status)
end end
end end
end end
...@@ -7,9 +7,5 @@ module Gitlab ...@@ -7,9 +7,5 @@ module Gitlab
@status = status @status = status
@message = message @message = message
end end
def to_json(opts = nil)
{ status: @status, message: @message }.to_json(opts)
end
end end
end end
...@@ -16,7 +16,7 @@ module Gitlab ...@@ -16,7 +16,7 @@ module Gitlab
if user_access.can_do_action?(:create_wiki) if user_access.can_do_action?(:create_wiki)
build_status_object(true) build_status_object(true)
else else
build_status_object(false, ERROR_MESSAGES[:write_to_wiki]) raise UnauthorizedError, ERROR_MESSAGES[:write_to_wiki]
end end
end end
end end
......
...@@ -23,29 +23,27 @@ describe Gitlab::Checks::ChangeAccess, lib: true do ...@@ -23,29 +23,27 @@ describe Gitlab::Checks::ChangeAccess, lib: true do
before { project.add_developer(user) } before { project.add_developer(user) }
context 'without failed checks' do context 'without failed checks' do
it "doesn't return any error" do it "doesn't raise an error" do
expect(subject.status).to be(true) expect { subject }.not_to raise_error
end end
end end
context 'when the user is not allowed to push code' do context 'when the user is not allowed to push code' do
it 'returns an error' do it 'raises an error' do
expect(user_access).to receive(:can_do_action?).with(:push_code).and_return(false) expect(user_access).to receive(:can_do_action?).with(:push_code).and_return(false)
expect(subject.status).to be(false) expect { subject }.to raise_error(Gitlab::GitAccess::UnauthorizedError, 'You are not allowed to push code to this project.')
expect(subject.message).to eq('You are not allowed to push code to this project.')
end end
end end
context 'tags check' do context 'tags check' do
let(:ref) { 'refs/tags/v1.0.0' } let(:ref) { 'refs/tags/v1.0.0' }
it 'returns an error if the user is not allowed to update tags' do it 'raises an error if the user is not allowed to update tags' do
allow(user_access).to receive(:can_do_action?).with(:push_code).and_return(true) allow(user_access).to receive(:can_do_action?).with(:push_code).and_return(true)
expect(user_access).to receive(:can_do_action?).with(:admin_project).and_return(false) expect(user_access).to receive(:can_do_action?).with(:admin_project).and_return(false)
expect(subject.status).to be(false) expect { subject }.to raise_error(Gitlab::GitAccess::UnauthorizedError, 'You are not allowed to change existing tags on this project.')
expect(subject.message).to eq('You are not allowed to change existing tags on this project.')
end end
context 'with protected tag' do context 'with protected tag' do
...@@ -59,8 +57,7 @@ describe Gitlab::Checks::ChangeAccess, lib: true do ...@@ -59,8 +57,7 @@ describe Gitlab::Checks::ChangeAccess, lib: true do
let(:newrev) { '0000000000000000000000000000000000000000' } let(:newrev) { '0000000000000000000000000000000000000000' }
it 'is prevented' do it 'is prevented' do
expect(subject.status).to be(false) expect { subject }.to raise_error(Gitlab::GitAccess::UnauthorizedError, /cannot be deleted/)
expect(subject.message).to include('cannot be deleted')
end end
end end
...@@ -69,8 +66,7 @@ describe Gitlab::Checks::ChangeAccess, lib: true do ...@@ -69,8 +66,7 @@ describe Gitlab::Checks::ChangeAccess, lib: true do
let(:newrev) { '54fcc214b94e78d7a41a9a8fe6d87a5e59500e51' } let(:newrev) { '54fcc214b94e78d7a41a9a8fe6d87a5e59500e51' }
it 'is prevented' do it 'is prevented' do
expect(subject.status).to be(false) expect { subject }.to raise_error(Gitlab::GitAccess::UnauthorizedError, /cannot be updated/)
expect(subject.message).to include('cannot be updated')
end end
end end
end end
...@@ -81,15 +77,14 @@ describe Gitlab::Checks::ChangeAccess, lib: true do ...@@ -81,15 +77,14 @@ describe Gitlab::Checks::ChangeAccess, lib: true do
let(:ref) { 'refs/tags/v9.1.0' } let(:ref) { 'refs/tags/v9.1.0' }
it 'prevents creation below access level' do it 'prevents creation below access level' do
expect(subject.status).to be(false) expect { subject }.to raise_error(Gitlab::GitAccess::UnauthorizedError, /allowed to create this tag as it is protected/)
expect(subject.message).to include('allowed to create this tag as it is protected')
end end
context 'when user has access' do context 'when user has access' do
let!(:protected_tag) { create(:protected_tag, :developers_can_create, project: project, name: 'v*') } let!(:protected_tag) { create(:protected_tag, :developers_can_create, project: project, name: 'v*') }
it 'allows tag creation' do it 'allows tag creation' do
expect(subject.status).to be(true) expect { subject }.not_to raise_error
end end
end end
end end
...@@ -101,9 +96,8 @@ describe Gitlab::Checks::ChangeAccess, lib: true do ...@@ -101,9 +96,8 @@ describe Gitlab::Checks::ChangeAccess, lib: true do
let(:newrev) { '0000000000000000000000000000000000000000' } let(:newrev) { '0000000000000000000000000000000000000000' }
let(:ref) { 'refs/heads/master' } let(:ref) { 'refs/heads/master' }
it 'returns an error' do it 'raises an error' do
expect(subject.status).to be(false) expect { subject }.to raise_error(Gitlab::GitAccess::UnauthorizedError, 'The default branch of a project cannot be deleted.')
expect(subject.message).to eq('The default branch of a project cannot be deleted.')
end end
end end
...@@ -113,27 +107,24 @@ describe Gitlab::Checks::ChangeAccess, lib: true do ...@@ -113,27 +107,24 @@ describe Gitlab::Checks::ChangeAccess, lib: true do
allow(ProtectedBranch).to receive(:protected?).with(project, 'feature').and_return(true) allow(ProtectedBranch).to receive(:protected?).with(project, 'feature').and_return(true)
end end
it 'returns an error if the user is not allowed to do forced pushes to protected branches' do it 'raises an error if the user is not allowed to do forced pushes to protected branches' do
expect(Gitlab::Checks::ForcePush).to receive(:force_push?).and_return(true) expect(Gitlab::Checks::ForcePush).to receive(:force_push?).and_return(true)
expect(subject.status).to be(false) expect { subject }.to raise_error(Gitlab::GitAccess::UnauthorizedError, 'You are not allowed to force push code to a protected branch on this project.')
expect(subject.message).to eq('You are not allowed to force push code to a protected branch on this project.')
end end
it 'returns an error if the user is not allowed to merge to protected branches' do it 'raises an error if the user is not allowed to merge to protected branches' do
expect_any_instance_of(Gitlab::Checks::MatchingMergeRequest).to receive(:match?).and_return(true) expect_any_instance_of(Gitlab::Checks::MatchingMergeRequest).to receive(:match?).and_return(true)
expect(user_access).to receive(:can_merge_to_branch?).and_return(false) expect(user_access).to receive(:can_merge_to_branch?).and_return(false)
expect(user_access).to receive(:can_push_to_branch?).and_return(false) expect(user_access).to receive(:can_push_to_branch?).and_return(false)
expect(subject.status).to be(false) expect { subject }.to raise_error(Gitlab::GitAccess::UnauthorizedError, 'You are not allowed to merge code into protected branches on this project.')
expect(subject.message).to eq('You are not allowed to merge code into protected branches on this project.')
end end
it 'returns an error if the user is not allowed to push to protected branches' do it 'raises an error if the user is not allowed to push to protected branches' do
expect(user_access).to receive(:can_push_to_branch?).and_return(false) expect(user_access).to receive(:can_push_to_branch?).and_return(false)
expect(subject.status).to be(false) expect { subject }.to raise_error(Gitlab::GitAccess::UnauthorizedError, 'You are not allowed to push code to protected branches on this project.')
expect(subject.message).to eq('You are not allowed to push code to protected branches on this project.')
end end
context 'branch deletion' do context 'branch deletion' do
...@@ -141,9 +132,8 @@ describe Gitlab::Checks::ChangeAccess, lib: true do ...@@ -141,9 +132,8 @@ describe Gitlab::Checks::ChangeAccess, lib: true do
let(:ref) { 'refs/heads/feature' } let(:ref) { 'refs/heads/feature' }
context 'if the user is not allowed to delete protected branches' do context 'if the user is not allowed to delete protected branches' do
it 'returns an error' do it 'raises an error' do
expect(subject.status).to be(false) expect { subject }.to raise_error(Gitlab::GitAccess::UnauthorizedError, 'You are not allowed to delete protected branches from this project. Only a project master or owner can delete a protected branch.')
expect(subject.message).to eq('You are not allowed to delete protected branches from this project. Only a project master or owner can delete a protected branch.')
end end
end end
...@@ -156,14 +146,13 @@ describe Gitlab::Checks::ChangeAccess, lib: true do ...@@ -156,14 +146,13 @@ describe Gitlab::Checks::ChangeAccess, lib: true do
let(:protocol) { 'web' } let(:protocol) { 'web' }
it 'allows branch deletion' do it 'allows branch deletion' do
expect(subject.status).to be(true) expect { subject }.not_to raise_error
end end
end end
context 'over SSH or HTTP' do context 'over SSH or HTTP' do
it 'returns an error' do it 'raises an error' do
expect(subject.status).to be(false) expect { subject }.to raise_error(Gitlab::GitAccess::UnauthorizedError, 'You can only delete protected branches using the web interface.')
expect(subject.message).to eq('You can only delete protected branches using the web interface.')
end end
end end
end end
......
...@@ -18,8 +18,7 @@ describe Gitlab::GitAccess, lib: true do ...@@ -18,8 +18,7 @@ describe Gitlab::GitAccess, lib: true do
describe '#check with single protocols allowed' do describe '#check with single protocols allowed' do
def disable_protocol(protocol) def disable_protocol(protocol)
settings = ::ApplicationSetting.create_from_defaults allow(Gitlab::ProtocolAccess).to receive(:allowed?).with(protocol).and_return(false)
settings.update_attribute(:enabled_git_access_protocol, protocol)
end end
context 'ssh disabled' do context 'ssh disabled' do
...@@ -28,11 +27,11 @@ describe Gitlab::GitAccess, lib: true do ...@@ -28,11 +27,11 @@ describe Gitlab::GitAccess, lib: true do
end end
it 'blocks ssh git push' do it 'blocks ssh git push' do
expect(access.check('git-receive-pack', '_any').allowed?).to be_falsey expect { push_access_check }.to raise_unauthorized('Git access over SSH is not allowed')
end end
it 'blocks ssh git pull' do it 'blocks ssh git pull' do
expect(access.check('git-upload-pack', '_any').allowed?).to be_falsey expect { pull_access_check }.to raise_unauthorized('Git access over SSH is not allowed')
end end
end end
...@@ -44,11 +43,11 @@ describe Gitlab::GitAccess, lib: true do ...@@ -44,11 +43,11 @@ describe Gitlab::GitAccess, lib: true do
end end
it 'blocks http push' do it 'blocks http push' do
expect(access.check('git-receive-pack', '_any').allowed?).to be_falsey expect { push_access_check }.to raise_unauthorized('Git access over HTTP is not allowed')
end end
it 'blocks http git pull' do it 'blocks http git pull' do
expect(access.check('git-upload-pack', '_any').allowed?).to be_falsey expect { pull_access_check }.to raise_unauthorized('Git access over HTTP is not allowed')
end end
end end
end end
...@@ -64,23 +63,21 @@ describe Gitlab::GitAccess, lib: true do ...@@ -64,23 +63,21 @@ describe Gitlab::GitAccess, lib: true do
before { deploy_key.projects << project } before { deploy_key.projects << project }
it 'allows pull access' do it 'allows pull access' do
expect(pull_access_check.allowed?).to be_truthy expect { pull_access_check }.not_to raise_error
end end
it 'allows push access' do it 'allows push access' do
expect(push_access_check.allowed?).to be_truthy expect { push_access_check }.not_to raise_error
end end
end end
context 'when the Deploykey does not have access to the project' do context 'when the Deploykey does not have access to the project' do
it 'blocks pulls with "not found"' do it 'blocks pulls with "not found"' do
expect(pull_access_check.allowed?).to be_falsey expect { pull_access_check }.to raise_not_found('The project you were looking for could not be found.')
expect(pull_access_check.message).to eq('The project you were looking for could not be found.')
end end
it 'blocks pushes with "not found"' do it 'blocks pushes with "not found"' do
expect(push_access_check.allowed?).to be_falsey expect { push_access_check }.to raise_not_found('The project you were looking for could not be found.')
expect(push_access_check.message).to eq('The project you were looking for could not be found.')
end end
end end
end end
...@@ -90,23 +87,21 @@ describe Gitlab::GitAccess, lib: true do ...@@ -90,23 +87,21 @@ describe Gitlab::GitAccess, lib: true do
before { project.team << [user, :master] } before { project.team << [user, :master] }
it 'allows pull access' do it 'allows pull access' do
expect(pull_access_check.allowed?).to be_truthy expect { pull_access_check }.not_to raise_error
end end
it 'allows push access' do it 'allows push access' do
expect(push_access_check.allowed?).to be_truthy expect { push_access_check }.not_to raise_error
end end
end end
context 'when the User cannot read the project' do context 'when the User cannot read the project' do
it 'blocks pulls with "not found"' do it 'blocks pulls with "not found"' do
expect(pull_access_check.allowed?).to be_falsey expect { pull_access_check }.to raise_not_found('The project you were looking for could not be found.')
expect(pull_access_check.message).to eq('The project you were looking for could not be found.')
end end
it 'blocks pushes with "not found"' do it 'blocks pushes with "not found"' do
expect(push_access_check.allowed?).to be_falsey expect { push_access_check }.to raise_not_found('The project you were looking for could not be found.')
expect(push_access_check.message).to eq('The project you were looking for could not be found.')
end end
end end
end end
...@@ -117,12 +112,11 @@ describe Gitlab::GitAccess, lib: true do ...@@ -117,12 +112,11 @@ describe Gitlab::GitAccess, lib: true do
let(:authentication_abilities) { build_authentication_abilities } let(:authentication_abilities) { build_authentication_abilities }
it 'allows pull access' do it 'allows pull access' do
expect(pull_access_check.allowed?).to be_truthy expect { pull_access_check }.not_to raise_error
end end
it 'does not block pushes with "not found"' do it 'does not block pushes with "not found"' do
expect(push_access_check.allowed?).to be_falsey expect { push_access_check }.to raise_unauthorized('You are not allowed to upload code for this project.')
expect(push_access_check.message).to eq('You are not allowed to upload code for this project.')
end end
end end
end end
...@@ -134,24 +128,21 @@ describe Gitlab::GitAccess, lib: true do ...@@ -134,24 +128,21 @@ describe Gitlab::GitAccess, lib: true do
let(:project) { create(:project, :repository, :public) } let(:project) { create(:project, :repository, :public) }
it 'allows pull access' do it 'allows pull access' do
expect(pull_access_check.allowed?).to be_truthy expect { pull_access_check }.not_to raise_error
end end
it 'does not block pushes with "not found"' do it 'does not block pushes with "not found"' do
expect(push_access_check.allowed?).to be_falsey expect { push_access_check }.to raise_unauthorized('You are not allowed to upload code for this project.')
expect(push_access_check.message).to eq('You are not allowed to upload code for this project.')
end end
end end
context 'when guests cannot read the project' do context 'when guests cannot read the project' do
it 'blocks pulls with "not found"' do it 'blocks pulls with "not found"' do
expect(pull_access_check.allowed?).to be_falsey expect { pull_access_check }.to raise_not_found('The project you were looking for could not be found.')
expect(pull_access_check.message).to eq('The project you were looking for could not be found.')
end end
it 'blocks pushes with "not found"' do it 'blocks pushes with "not found"' do
expect(push_access_check.allowed?).to be_falsey expect { push_access_check }.to raise_not_found('The project you were looking for could not be found.')
expect(push_access_check.message).to eq('The project you were looking for could not be found.')
end end
end end
end end
...@@ -161,10 +152,8 @@ describe Gitlab::GitAccess, lib: true do ...@@ -161,10 +152,8 @@ describe Gitlab::GitAccess, lib: true do
let(:project) { nil } let(:project) { nil }
it 'blocks any command with "not found"' do it 'blocks any command with "not found"' do
expect(pull_access_check.allowed?).to be_falsey expect { pull_access_check }.to raise_not_found('The project you were looking for could not be found.')
expect(pull_access_check.message).to eq('The project you were looking for could not be found.') expect { push_access_check }.to raise_not_found('The project you were looking for could not be found.')
expect(push_access_check.allowed?).to be_falsey
expect(push_access_check.message).to eq('The project you were looking for could not be found.')
end end
end end
end end
...@@ -181,13 +170,11 @@ describe Gitlab::GitAccess, lib: true do ...@@ -181,13 +170,11 @@ describe Gitlab::GitAccess, lib: true do
end end
context 'when calling git-upload-pack' do context 'when calling git-upload-pack' do
subject { access.check('git-upload-pack', '_any') } it { expect { pull_access_check }.to raise_unauthorized('The command "git-upload-pack" is not allowed.') }
it { expect(subject.allowed?).to be_falsey }
it { expect(subject.message).to eq('The command "git-upload-pack" is not allowed.') }
end end
context 'when calling git-receive-pack' do context 'when calling git-receive-pack' do
it { expect(access.check('git-receive-pack', '_any').allowed?).to be_truthy } it { expect { push_access_check }.not_to raise_error }
end end
end end
...@@ -197,26 +184,22 @@ describe Gitlab::GitAccess, lib: true do ...@@ -197,26 +184,22 @@ describe Gitlab::GitAccess, lib: true do
end end
context 'when calling git-receive-pack' do context 'when calling git-receive-pack' do
subject { access.check('git-receive-pack', '_any') } it { expect { push_access_check }.to raise_unauthorized('The command "git-receive-pack" is not allowed.') }
it { expect(subject.allowed?).to be_falsey }
it { expect(subject.message).to eq('The command "git-receive-pack" is not allowed.') }
end end
context 'when calling git-upload-pack' do context 'when calling git-upload-pack' do
it { expect(access.check('git-upload-pack', '_any').allowed?).to be_truthy } it { expect { pull_access_check }.not_to raise_error }
end end
end end
end end
end end
describe '#check_download_access!' do describe '#check_download_access!' do
subject { access.check('git-upload-pack', '_any') }
describe 'master permissions' do describe 'master permissions' do
before { project.team << [user, :master] } before { project.team << [user, :master] }
context 'pull code' do context 'pull code' do
it { expect(subject.allowed?).to be_truthy } it { expect { pull_access_check }.not_to raise_error }
end end
end end
...@@ -224,8 +207,7 @@ describe Gitlab::GitAccess, lib: true do ...@@ -224,8 +207,7 @@ describe Gitlab::GitAccess, lib: true do
before { project.team << [user, :guest] } before { project.team << [user, :guest] }
context 'pull code' do context 'pull code' do
it { expect(subject.allowed?).to be_falsey } it { expect { pull_access_check }.to raise_unauthorized('You are not allowed to download code from this project.') }
it { expect(subject.message).to match(/You are not allowed to download code/) }
end end
end end
...@@ -236,24 +218,22 @@ describe Gitlab::GitAccess, lib: true do ...@@ -236,24 +218,22 @@ describe Gitlab::GitAccess, lib: true do
end end
context 'pull code' do context 'pull code' do
it { expect(subject.allowed?).to be_falsey } it { expect { pull_access_check }.to raise_unauthorized('Your account has been blocked.') }
it { expect(subject.message).to match(/Your account has been blocked/) }
end end
end end
describe 'without access to project' do describe 'without access to project' do
context 'pull code' do context 'pull code' do
it { expect(subject.allowed?).to be_falsey } it { expect { pull_access_check }.to raise_not_found('The project you were looking for could not be found.') }
end end
context 'when project is public' do context 'when project is public' do
let(:public_project) { create(:project, :public, :repository) } let(:public_project) { create(:project, :public, :repository) }
let(:guest_access) { Gitlab::GitAccess.new(nil, public_project, 'web', authentication_abilities: []) } let(:access) { Gitlab::GitAccess.new(nil, public_project, 'web', authentication_abilities: []) }
subject { guest_access.check('git-upload-pack', '_any') }
context 'when repository is enabled' do context 'when repository is enabled' do
it 'give access to download code' do it 'give access to download code' do
expect(subject.allowed?).to be_truthy expect { pull_access_check }.not_to raise_error
end end
end end
...@@ -261,8 +241,7 @@ describe Gitlab::GitAccess, lib: true do ...@@ -261,8 +241,7 @@ describe Gitlab::GitAccess, lib: true do
it 'does not give access to download code' do it 'does not give access to download code' do
public_project.project_feature.update_attribute(:repository_access_level, ProjectFeature::DISABLED) public_project.project_feature.update_attribute(:repository_access_level, ProjectFeature::DISABLED)
expect(subject.allowed?).to be_falsey expect { pull_access_check }.to raise_unauthorized('You are not allowed to download code from this project.')
expect(subject.message).to match(/You are not allowed to download code/)
end end
end end
end end
...@@ -276,26 +255,26 @@ describe Gitlab::GitAccess, lib: true do ...@@ -276,26 +255,26 @@ describe Gitlab::GitAccess, lib: true do
context 'when project is authorized' do context 'when project is authorized' do
before { key.projects << project } before { key.projects << project }
it { expect(subject).to be_allowed } it { expect { pull_access_check }.not_to raise_error }
end end
context 'when unauthorized' do context 'when unauthorized' do
context 'from public project' do context 'from public project' do
let(:project) { create(:project, :public, :repository) } let(:project) { create(:project, :public, :repository) }
it { expect(subject).to be_allowed } it { expect { pull_access_check }.not_to raise_error }
end end
context 'from internal project' do context 'from internal project' do
let(:project) { create(:project, :internal, :repository) } let(:project) { create(:project, :internal, :repository) }
it { expect(subject).not_to be_allowed } it { expect { pull_access_check }.to raise_not_found('The project you were looking for could not be found.') }
end end
context 'from private project' do context 'from private project' do
let(:project) { create(:project, :private, :repository) } let(:project) { create(:project, :private, :repository) }
it { expect(subject).not_to be_allowed } it { expect { pull_access_check }.to raise_not_found('The project you were looking for could not be found.') }
end end
end end
end end
...@@ -308,7 +287,7 @@ describe Gitlab::GitAccess, lib: true do ...@@ -308,7 +287,7 @@ describe Gitlab::GitAccess, lib: true do
let(:project) { create(:project, :repository, namespace: user.namespace) } let(:project) { create(:project, :repository, namespace: user.namespace) }
context 'pull code' do context 'pull code' do
it { expect(subject).to be_allowed } it { expect { pull_access_check }.not_to raise_error }
end end
end end
...@@ -316,7 +295,7 @@ describe Gitlab::GitAccess, lib: true do ...@@ -316,7 +295,7 @@ describe Gitlab::GitAccess, lib: true do
before { project.team << [user, :reporter] } before { project.team << [user, :reporter] }
context 'pull code' do context 'pull code' do
it { expect(subject).to be_allowed } it { expect { pull_access_check }.not_to raise_error }
end end
end end
...@@ -327,13 +306,13 @@ describe Gitlab::GitAccess, lib: true do ...@@ -327,13 +306,13 @@ describe Gitlab::GitAccess, lib: true do
before { project.team << [user, :reporter] } before { project.team << [user, :reporter] }
context 'pull code' do context 'pull code' do
it { expect(subject).to be_allowed } it { expect { pull_access_check }.not_to raise_error }
end end
end end
context 'when is not member of the project' do context 'when is not member of the project' do
context 'pull code' do context 'pull code' do
it { expect(subject).not_to be_allowed } it { expect { pull_access_check }.to raise_unauthorized('You are not allowed to download code from this project.') }
end end
end end
end end
...@@ -342,7 +321,7 @@ describe Gitlab::GitAccess, lib: true do ...@@ -342,7 +321,7 @@ describe Gitlab::GitAccess, lib: true do
let(:actor) { :ci } let(:actor) { :ci }
context 'pull code' do context 'pull code' do
it { expect(subject).to be_allowed } it { expect { pull_access_check }.not_to raise_error }
end end
end end
end end
...@@ -532,42 +511,32 @@ describe Gitlab::GitAccess, lib: true do ...@@ -532,42 +511,32 @@ describe Gitlab::GitAccess, lib: true do
end end
end end
shared_examples 'pushing code' do |can| describe 'build authentication abilities' do
subject { access.check('git-receive-pack', '_any') } let(:authentication_abilities) { build_authentication_abilities }
context 'when project is authorized' do context 'when project is authorized' do
before { authorize } before { project.team << [user, :reporter] }
it { expect(subject).public_send(can, be_allowed) } it { expect { push_access_check }.to raise_unauthorized('You are not allowed to upload code for this project.') }
end end
context 'when unauthorized' do context 'when unauthorized' do
context 'to public project' do context 'to public project' do
let(:project) { create(:project, :public, :repository) } let(:project) { create(:project, :public, :repository) }
it { expect(subject).not_to be_allowed } it { expect { push_access_check }.to raise_unauthorized('You are not allowed to upload code for this project.') }
end end
context 'to internal project' do context 'to internal project' do
let(:project) { create(:project, :internal, :repository) } let(:project) { create(:project, :internal, :repository) }
it { expect(subject).not_to be_allowed } it { expect { push_access_check }.to raise_unauthorized('You are not allowed to upload code for this project.') }
end end
context 'to private project' do context 'to private project' do
let(:project) { create(:project, :private, :repository) } let(:project) { create(:project, :private, :repository) }
it { expect(subject).not_to be_allowed } it { expect { push_access_check }.to raise_not_found('The project you were looking for could not be found.') }
end
end
end
describe 'build authentication abilities' do
let(:authentication_abilities) { build_authentication_abilities }
it_behaves_like 'pushing code', :not_to do
def authorize
project.team << [user, :reporter]
end end
end end
end end
...@@ -579,9 +548,29 @@ describe Gitlab::GitAccess, lib: true do ...@@ -579,9 +548,29 @@ describe Gitlab::GitAccess, lib: true do
context 'when deploy_key can push' do context 'when deploy_key can push' do
let(:can_push) { true } let(:can_push) { true }
it_behaves_like 'pushing code', :to do context 'when project is authorized' do
def authorize before { key.projects << project }
key.projects << project
it { expect { push_access_check }.not_to raise_error }
end
context 'when unauthorized' do
context 'to public project' do
let(:project) { create(:project, :public, :repository) }
it { expect { push_access_check }.to raise_unauthorized('This deploy key does not have write access to this project.') }
end
context 'to internal project' do
let(:project) { create(:project, :internal, :repository) }
it { expect { push_access_check }.to raise_not_found('The project you were looking for could not be found.') }
end
context 'to private project' do
let(:project) { create(:project, :private, :repository) }
it { expect { push_access_check }.to raise_not_found('The project you were looking for could not be found.') }
end end
end end
end end
...@@ -589,9 +578,29 @@ describe Gitlab::GitAccess, lib: true do ...@@ -589,9 +578,29 @@ describe Gitlab::GitAccess, lib: true do
context 'when deploy_key cannot push' do context 'when deploy_key cannot push' do
let(:can_push) { false } let(:can_push) { false }
it_behaves_like 'pushing code', :not_to do context 'when project is authorized' do
def authorize before { key.projects << project }
key.projects << project
it { expect { push_access_check }.to raise_unauthorized('This deploy key does not have write access to this project.') }
end
context 'when unauthorized' do
context 'to public project' do
let(:project) { create(:project, :public, :repository) }
it { expect { push_access_check }.to raise_unauthorized('This deploy key does not have write access to this project.') }
end
context 'to internal project' do
let(:project) { create(:project, :internal, :repository) }
it { expect { push_access_check }.to raise_not_found('The project you were looking for could not be found.') }
end
context 'to private project' do
let(:project) { create(:project, :private, :repository) }
it { expect { push_access_check }.to raise_not_found('The project you were looking for could not be found.') }
end end
end end
end end
...@@ -599,6 +608,14 @@ describe Gitlab::GitAccess, lib: true do ...@@ -599,6 +608,14 @@ describe Gitlab::GitAccess, lib: true do
private private
def raise_unauthorized(message)
raise_error(Gitlab::GitAccess::UnauthorizedError, message)
end
def raise_not_found(message)
raise_error(Gitlab::GitAccess::NotFoundError, message)
end
def build_authentication_abilities def build_authentication_abilities
[ [
:read_project, :read_project,
......
...@@ -20,7 +20,7 @@ describe Gitlab::GitAccessWiki, lib: true do ...@@ -20,7 +20,7 @@ describe Gitlab::GitAccessWiki, lib: true do
subject { access.check('git-receive-pack', changes) } subject { access.check('git-receive-pack', changes) }
it { expect(subject.allowed?).to be_truthy } it { expect { subject }.not_to raise_error }
end end
def changes def changes
...@@ -36,7 +36,7 @@ describe Gitlab::GitAccessWiki, lib: true do ...@@ -36,7 +36,7 @@ describe Gitlab::GitAccessWiki, lib: true do
context 'when wiki feature is enabled' do context 'when wiki feature is enabled' do
it 'give access to download wiki code' do it 'give access to download wiki code' do
expect(subject.allowed?).to be_truthy expect { subject }.not_to raise_error
end end
end end
...@@ -44,8 +44,7 @@ describe Gitlab::GitAccessWiki, lib: true do ...@@ -44,8 +44,7 @@ describe Gitlab::GitAccessWiki, lib: true do
it 'does not give access to download wiki code' do it 'does not give access to download wiki code' do
project.project_feature.update_attribute(:wiki_access_level, ProjectFeature::DISABLED) project.project_feature.update_attribute(:wiki_access_level, ProjectFeature::DISABLED)
expect(subject.allowed?).to be_falsey expect { subject }.to raise_error(Gitlab::GitAccess::UnauthorizedError, 'You are not allowed to download code from this project.')
expect(subject.message).to match(/You are not allowed to download code/)
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