Commit 07ab4ad6 authored by Rémy Coutable's avatar Rémy Coutable

Merge branch 'sh-fix-lfs-write-deploy-keys' into 'master'

Fix Error 500 when pushing LFS objects with a write deploy key

Closes #39467

See merge request gitlab-org/gitlab-ce!15039
parents 9e294180 0232450c
...@@ -74,8 +74,9 @@ module LfsRequest ...@@ -74,8 +74,9 @@ module LfsRequest
def lfs_upload_access? def lfs_upload_access?
return false unless project.lfs_enabled? return false unless project.lfs_enabled?
return false unless has_authentication_ability?(:push_code)
has_authentication_ability?(:push_code) && can?(user, :push_code, project) lfs_deploy_token? || can?(user, :push_code, project)
end end
def lfs_deploy_token? def lfs_deploy_token?
......
...@@ -25,7 +25,7 @@ module Gitlab ...@@ -25,7 +25,7 @@ module Gitlab
result = result =
service_request_check(login, password, project) || service_request_check(login, password, project) ||
build_access_token_check(login, password) || build_access_token_check(login, password) ||
lfs_token_check(login, password) || lfs_token_check(login, password, project) ||
oauth_access_token_check(login, password) || oauth_access_token_check(login, password) ||
personal_access_token_check(password) || personal_access_token_check(password) ||
user_with_password_for_git(login, password) || user_with_password_for_git(login, password) ||
...@@ -146,7 +146,7 @@ module Gitlab ...@@ -146,7 +146,7 @@ module Gitlab
end.flatten.uniq end.flatten.uniq
end end
def lfs_token_check(login, password) def lfs_token_check(login, password, project)
deploy_key_matches = login.match(/\Alfs\+deploy-key-(\d+)\z/) deploy_key_matches = login.match(/\Alfs\+deploy-key-(\d+)\z/)
actor = actor =
...@@ -163,6 +163,8 @@ module Gitlab ...@@ -163,6 +163,8 @@ module Gitlab
authentication_abilities = authentication_abilities =
if token_handler.user? if token_handler.user?
full_authentication_abilities full_authentication_abilities
elsif token_handler.deploy_key_pushable?(project)
read_write_authentication_abilities
else else
read_authentication_abilities read_authentication_abilities
end end
...@@ -208,10 +210,15 @@ module Gitlab ...@@ -208,10 +210,15 @@ module Gitlab
] ]
end end
def full_authentication_abilities def read_write_authentication_abilities
read_authentication_abilities + [ read_authentication_abilities + [
:push_code, :push_code,
:create_container_image, :create_container_image
]
end
def full_authentication_abilities
read_write_authentication_abilities + [
:admin_container_image :admin_container_image
] ]
end end
......
...@@ -27,6 +27,10 @@ module Gitlab ...@@ -27,6 +27,10 @@ module Gitlab
end end
end end
def deploy_key_pushable?(project)
actor.is_a?(DeployKey) && actor.can_push_to?(project)
end
def user? def user?
actor.is_a?(User) actor.is_a?(User)
end end
......
...@@ -133,6 +133,25 @@ describe Gitlab::Auth do ...@@ -133,6 +133,25 @@ describe Gitlab::Auth do
gl_auth.find_for_git_client(user.username, token, project: nil, ip: 'ip') gl_auth.find_for_git_client(user.username, token, project: nil, ip: 'ip')
end end
it 'grants deploy key write permissions' do
project = create(:project)
key = create(:deploy_key, can_push: true)
create(:deploy_keys_project, deploy_key: key, project: project)
token = Gitlab::LfsToken.new(key).token
expect(gl_auth).to receive(:rate_limit!).with('ip', success: true, login: "lfs+deploy-key-#{key.id}")
expect(gl_auth.find_for_git_client("lfs+deploy-key-#{key.id}", token, project: project, ip: 'ip')).to eq(Gitlab::Auth::Result.new(key, nil, :lfs_deploy_token, read_write_authentication_abilities))
end
it 'does not grant deploy key write permissions' do
project = create(:project)
key = create(:deploy_key, can_push: true)
token = Gitlab::LfsToken.new(key).token
expect(gl_auth).to receive(:rate_limit!).with('ip', success: true, login: "lfs+deploy-key-#{key.id}")
expect(gl_auth.find_for_git_client("lfs+deploy-key-#{key.id}", token, project: project, ip: 'ip')).to eq(Gitlab::Auth::Result.new(key, nil, :lfs_deploy_token, read_authentication_abilities))
end
end end
context 'while using OAuth tokens as passwords' do context 'while using OAuth tokens as passwords' do
...@@ -326,10 +345,15 @@ describe Gitlab::Auth do ...@@ -326,10 +345,15 @@ describe Gitlab::Auth do
] ]
end end
def full_authentication_abilities def read_write_authentication_abilities
read_authentication_abilities + [ read_authentication_abilities + [
:push_code, :push_code,
:create_container_image, :create_container_image
]
end
def full_authentication_abilities
read_write_authentication_abilities + [
:admin_container_image :admin_container_image
] ]
end end
......
...@@ -654,6 +654,20 @@ describe 'Git LFS API and storage' do ...@@ -654,6 +654,20 @@ describe 'Git LFS API and storage' do
} }
end end
shared_examples 'pushes new LFS objects' do
let(:sample_size) { 150.megabytes }
let(:sample_oid) { '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897' }
it 'responds with upload hypermedia link' do
expect(response).to have_gitlab_http_status(200)
expect(json_response['objects']).to be_kind_of(Array)
expect(json_response['objects'].first['oid']).to eq(sample_oid)
expect(json_response['objects'].first['size']).to eq(sample_size)
expect(json_response['objects'].first['actions']['upload']['href']).to eq("#{Gitlab.config.gitlab.url}/#{project.full_path}.git/gitlab-lfs/objects/#{sample_oid}/#{sample_size}")
expect(json_response['objects'].first['actions']['upload']['header']).to eq('Authorization' => authorization)
end
end
describe 'when request is authenticated' do describe 'when request is authenticated' do
describe 'when user has project push access' do describe 'when user has project push access' do
let(:authorization) { authorize_user } let(:authorization) { authorize_user }
...@@ -684,27 +698,7 @@ describe 'Git LFS API and storage' do ...@@ -684,27 +698,7 @@ describe 'Git LFS API and storage' do
end end
context 'when pushing a lfs object that does not exist' do context 'when pushing a lfs object that does not exist' do
let(:body) do it_behaves_like 'pushes new LFS objects'
{
'operation' => 'upload',
'objects' => [
{ 'oid' => '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897',
'size' => 1575078 }
]
}
end
it 'responds with status 200' do
expect(response).to have_gitlab_http_status(200)
end
it 'responds with upload hypermedia link' do
expect(json_response['objects']).to be_kind_of(Array)
expect(json_response['objects'].first['oid']).to eq("91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897")
expect(json_response['objects'].first['size']).to eq(1575078)
expect(json_response['objects'].first['actions']['upload']['href']).to eq("#{Gitlab.config.gitlab.url}/#{project.full_path}.git/gitlab-lfs/objects/91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897/1575078")
expect(json_response['objects'].first['actions']['upload']['header']).to eq('Authorization' => authorization)
end
end end
context 'when pushing one new and one existing lfs object' do context 'when pushing one new and one existing lfs object' do
...@@ -785,6 +779,17 @@ describe 'Git LFS API and storage' do ...@@ -785,6 +779,17 @@ describe 'Git LFS API and storage' do
end end
end end
end end
context 'when deploy key has project push access' do
let(:key) { create(:deploy_key, can_push: true) }
let(:authorization) { authorize_deploy_key }
let(:update_user_permissions) do
project.deploy_keys << key
end
it_behaves_like 'pushes new LFS objects'
end
end end
context 'when user is not authenticated' do context 'when user is not authenticated' do
......
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