Commit 4aa72eac authored by Stan Hu's avatar Stan Hu

Merge branch 'ash.mckenzie/geo-git-push-ssh-proxy-primary' into 'master'

Geo: backend support to allow Secondary node to push to a Primary as push proxying

See merge request gitlab-org/gitlab-ee!6455
parents 482577c6 90f0145e
......@@ -6,11 +6,24 @@ module EE
override :render_ok
def render_ok
set_workhorse_internal_api_content_type
render json: ::Gitlab::Workhorse.git_http_ok(repository, wiki?, user, action_name, show_all_refs: geo_request?)
end
private
def user
super || geo_push_user&.user
end
def geo_push_user
@geo_push_user ||= ::Geo::PushUser.new_from_headers(request.headers)
end
def geo_push_user_headers_provided?
::Geo::PushUser.needed_headers_provided?(request.headers)
end
def geo_request?
::Gitlab::Geo::JwtRequestDecoder.geo_auth_attempt?(request.headers['Authorization'])
end
......@@ -21,9 +34,11 @@ module EE
override :access_actor
def access_actor
return :geo if geo?
return super unless geo?
return :geo unless geo_push_user_headers_provided?
return geo_push_user.user if geo_push_user.user
super
raise ::Gitlab::GitAccess::UnauthorizedError, 'Geo push user is invalid.'
end
override :authenticate_user
......@@ -32,7 +47,7 @@ module EE
payload = ::Gitlab::Geo::JwtRequestDecoder.new(request.headers['Authorization']).decode
if payload
@authentication_result = ::Gitlab::Auth::Result.new(nil, project, :geo, [:download_code]) # rubocop:disable Gitlab/ModuleWithInstanceVariables
@authentication_result = ::Gitlab::Auth::Result.new(nil, project, :geo, [:download_code, :push_code]) # rubocop:disable Gitlab/ModuleWithInstanceVariables
return # grant access
end
......
# frozen_string_literal: true
class Geo::PushUser
include ::Gitlab::Identifier
def initialize(gl_id)
@gl_id = gl_id
end
def self.needed_headers_provided?(headers)
headers['Geo-GL-Id'].present?
end
def self.new_from_headers(headers)
return nil unless needed_headers_provided?(headers)
new(headers['Geo-GL-Id'])
end
def user
@user ||= identify_using_ssh_key(gl_id)
end
private
attr_reader :gl_id
end
---
title: Allow push_code when auth'd via Geo JWT
merge_request: 6455
author:
type: changed
......@@ -248,12 +248,23 @@ describe Gitlab::GitAccess do
end
end
describe 'Geo system permissions' do
let(:actor) { :geo }
it { expect { pull_changes }.not_to raise_error }
it { expect { push_changes }.to raise_unauthorized(Gitlab::GitAccess::ERROR_MESSAGES[:push_code]) }
end
private
def push_changes(changes = '_any')
access.check('git-receive-pack', changes)
end
def pull_changes(changes = '_any')
access.check('git-upload-pack', changes)
end
def raise_unauthorized(message)
raise_error(Gitlab::GitAccess::UnauthorizedError, message)
end
......
# frozen_string_literal: true
require 'spec_helper'
describe Geo::PushUser do
let!(:user) { create(:user) }
let!(:key) { create(:key, user: user) }
let(:gl_id) { "key-#{key.id}" }
subject { described_class.new(gl_id) }
describe '.needed_headers_provided?' do
where(:headers) do
[
{},
{ 'Geo-GL-Id' => nil },
{ 'Geo-GL-Id' => '' }
]
end
with_them do
it 'returns false' do
expect(described_class.needed_headers_provided?(headers)).to be(false)
end
end
context 'where gl_id is not nil' do
let(:headers) do
{ 'Geo-GL-Id' => gl_id }
end
it 'returns true' do
expect(described_class.needed_headers_provided?(headers)).to be(true)
end
end
end
describe '.new_from_headers' do
where(:headers) do
[
{},
{ 'Geo-GL-Id' => nil },
{ 'Geo-GL-Id' => '' }
]
end
with_them do
it 'returns false' do
expect(described_class.new_from_headers(headers)).to be_nil
end
end
context 'where gl_id is not nil' do
let(:headers) do
{ 'Geo-GL-Id' => gl_id }
end
it 'returns an instance of Geo::PushUser' do
expect(described_class.new_from_headers(headers)).to be_a(described_class)
end
end
end
describe '#user' do
context 'with a junk gl_id' do
let(:gl_id) { "test" }
it 'returns nil' do
expect(subject.user).to be_nil
end
end
context 'with an unsupported gl_id type' do
let(:gl_id) { "user-#{user.id}" }
it 'returns nil' do
expect(subject.user).to be_nil
end
end
context 'when the User associated to gl_id matches the User associated to gl_username' do
it 'returns a User' do
expect(subject.user).to be_a(User)
end
end
end
end
This diff is collapsed.
......@@ -50,6 +50,7 @@ module Gitlab
def push_checks
unless can_push?
# You are not allowed to push code to this project.
raise GitAccess::UnauthorizedError, ERROR_MESSAGES[:push_code]
end
end
......
......@@ -236,11 +236,13 @@ module Gitlab
# TODO: please clean this up
def check_push_access!
if project.repository_read_only?
# The repository is temporarily read-only. Please try again later.
raise UnauthorizedError, ERROR_MESSAGES[:read_only]
end
if deploy_key?
unless deploy_key.can_push_to?(project)
# This deploy key does not have write access to this project.
raise UnauthorizedError, ERROR_MESSAGES[:deploy_key_upload]
end
elsif user
......@@ -248,6 +250,7 @@ module Gitlab
elsif authed_via_jwt?
# Authenticated via JWT
else
# You are not allowed to upload code for this project.
raise UnauthorizedError, ERROR_MESSAGES[:upload]
end
......
......@@ -1165,13 +1165,6 @@ describe Gitlab::GitAccess do
end
end
describe 'Geo system permissions' do
let(:actor) { :geo }
it { expect { pull_access_check }.not_to raise_error }
it { expect { push_access_check }.to raise_unauthorized(Gitlab::GitAccess::ERROR_MESSAGES[:upload]) }
end
context 'terms are enforced' do
before do
enforce_terms
......
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