Commit 2bdf08e7 authored by Ash McKenzie's avatar Ash McKenzie

Merge remote-tracking branch 'origin/master' into ash.mckenzie/srp-refactor

parents a686b9a0 e3fead94
v8.0.0
- SSH certificate support (!207)
v7.2.0 v7.2.0
- Update gitaly-proto to 0.109.0 (!216) - Update gitaly-proto to 0.109.0 (!216)
......
...@@ -5,19 +5,19 @@ unless ENV['SSH_CONNECTION'] ...@@ -5,19 +5,19 @@ unless ENV['SSH_CONNECTION']
exit exit
end end
key_str = /key-[0-9]+/.match(ARGV.join).to_s
original_cmd = ENV.delete('SSH_ORIGINAL_COMMAND') original_cmd = ENV.delete('SSH_ORIGINAL_COMMAND')
require_relative '../lib/gitlab_init' require_relative '../lib/gitlab_init'
# #
# #
# GitLab shell, invoked from ~/.ssh/authorized_keys # GitLab shell, invoked from ~/.ssh/authorized_keys or from an
# AuthorizedPrincipalsCommand in the key-less SSH CERT mode.
# #
# #
require File.join(ROOT_PATH, 'lib', 'gitlab_shell') require File.join(ROOT_PATH, 'lib', 'gitlab_shell')
if GitlabShell.new(key_str).exec(original_cmd) if GitlabShell.new(ARGV.join).exec(original_cmd)
exit 0 exit 0
else else
exit 1 exit 1
......
#!/usr/bin/env ruby
#
# GitLab shell authorized principals helper. Emits the same sort of
# command="..." line as gitlab-shell-authorized-principals-check, with
# the right options.
#
# Ex.
# bin/gitlab-shell-authorized-keys-check <key-id> <principal1> [<principal2>...]
#
# Returns one line per principal passed in, e.g.:
# command="/bin/gitlab-shell username-{KEY_ID}",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty {PRINCIPAL}
# [command="/bin/gitlab-shell username-{KEY_ID}",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty {PRINCIPAL2}]
#
# Expects to be called by the SSH daemon, via configuration like:
# AuthorizedPrincipalsCommandUser root
# AuthorizedPrincipalsCommand /bin/gitlab-shell-authorized-principals-check git %i sshUsers
abort "# Wrong number of arguments. #{ARGV.size}. Usage:
# gitlab-shell-authorized-principals-check <key-id> <principal1> [<principal2>...]" unless ARGV.size >= 2
key_id = ARGV[0]
abort '# No key_id provided' if key_id.nil? || key_id == ''
principals = ARGV[1..-1]
principals.each { |principal|
abort '# An invalid principal was provided' if principal.nil? || principal == ''
}
require_relative '../lib/gitlab_init'
require_relative '../lib/gitlab_net'
require_relative '../lib/gitlab_keys'
principals.each { |principal|
puts GitlabKeys.principal_line("username-#{key_id}", principal.dup)
}
...@@ -3,8 +3,8 @@ require_relative '../gitlab_logger' ...@@ -3,8 +3,8 @@ require_relative '../gitlab_logger'
module Action module Action
class API2FARecovery < Base class API2FARecovery < Base
def initialize(key) def initialize(actor)
@key = key @actor = actor
end end
def execute(_, _) def execute(_, _)
...@@ -13,7 +13,7 @@ module Action ...@@ -13,7 +13,7 @@ module Action
private private
attr_reader :key attr_reader :actor
def continue?(question) def continue?(question)
puts "#{question} (yes/no)" puts "#{question} (yes/no)"
...@@ -34,10 +34,10 @@ module Action ...@@ -34,10 +34,10 @@ module Action
return return
end end
resp = api.two_factor_recovery_codes(key.key_id) resp = api.two_factor_recovery_codes(self)
if resp['success'] if resp['success']
codes = resp['recovery_codes'].join("\n") codes = resp['recovery_codes'].join("\n")
$logger.info('API 2FA recovery success', user: key.log_username) $logger.info('API 2FA recovery success', user: actor.log_username)
puts "Your two-factor authentication recovery codes are:\n\n" \ puts "Your two-factor authentication recovery codes are:\n\n" \
"#{codes}\n\n" \ "#{codes}\n\n" \
"During sign in, use one of the codes above when prompted for\n" \ "During sign in, use one of the codes above when prompted for\n" \
...@@ -45,7 +45,7 @@ module Action ...@@ -45,7 +45,7 @@ module Action
"a new device so you do not lose access to your account again." "a new device so you do not lose access to your account again."
true true
else else
$logger.info('API 2FA recovery error', user: key.log_username) $logger.info('API 2FA recovery error', user: actor.log_username)
puts "An error occurred while trying to generate new recovery codes.\n" \ puts "An error occurred while trying to generate new recovery codes.\n" \
"#{resp['message']}" "#{resp['message']}"
end end
......
...@@ -3,15 +3,15 @@ require_relative '../gitlab_logger' ...@@ -3,15 +3,15 @@ require_relative '../gitlab_logger'
module Action module Action
class GitLFSAuthenticate < Base class GitLFSAuthenticate < Base
def initialize(key, repo_name) def initialize(actor, repo_name)
@key = key @actor = actor
@repo_name = repo_name @repo_name = repo_name
end end
def execute(_, _) def execute(_, _)
GitlabMetrics.measure('lfs-authenticate') do GitlabMetrics.measure('lfs-authenticate') do
$logger.info('Processing LFS authentication', user: key.log_username) $logger.info('Processing LFS authentication', user: actor.log_username)
lfs_access = api.lfs_authenticate(key.key_id, repo_name) lfs_access = api.lfs_authenticate(self, repo_name)
return unless lfs_access return unless lfs_access
puts lfs_access.authentication_payload puts lfs_access.authentication_payload
...@@ -21,6 +21,6 @@ module Action ...@@ -21,6 +21,6 @@ module Action
private private
attr_reader :key, :repo_name attr_reader :actor, :repo_name
end end
end end
require_relative 'actor/base' require_relative 'actor/base'
require_relative 'actor/key' require_relative 'actor/key'
require_relative 'actor/user' require_relative 'actor/user'
require_relative 'actor/username'
module Actor module Actor
class UnsupportedActorError < StandardError; end class UnsupportedActorError < StandardError; end
...@@ -11,6 +12,8 @@ module Actor ...@@ -11,6 +12,8 @@ module Actor
Key.from(str, audit_usernames: audit_usernames) Key.from(str, audit_usernames: audit_usernames)
when User.id_regex when User.id_regex
User.from(str, audit_usernames: audit_usernames) User.from(str, audit_usernames: audit_usernames)
when Username.id_regex
Username.from(str, audit_usernames: audit_usernames)
else else
raise UnsupportedActorError raise UnsupportedActorError
end end
......
...@@ -31,6 +31,10 @@ module Actor ...@@ -31,6 +31,10 @@ module Actor
"#{self.class.identifier_prefix}-#{id}" "#{self.class.identifier_prefix}-#{id}"
end end
def identifier_key
self.class.identifier_key
end
def log_username def log_username
audit_usernames? ? username : "#{klass_name.downcase} with identifier #{identifier}" audit_usernames? ? username : "#{klass_name.downcase} with identifier #{identifier}"
end end
......
...@@ -21,7 +21,7 @@ module Actor ...@@ -21,7 +21,7 @@ module Actor
def username def username
@username ||= begin @username ||= begin
user = GitlabNet.new.discover(key_id) user = GitlabNet.new.discover(self)
user ? "@#{user['username']}" : ANONYMOUS_USER user ? "@#{user['username']}" : ANONYMOUS_USER
end end
end end
......
require_relative 'base'
module Actor
class Username < Base
alias username identifier
def self.identifier_prefix
'username'.freeze
end
def self.identifier_key
'username'.freeze
end
def self.id_regex
/\Ausername\-\d+\Z/
end
end
end
...@@ -9,12 +9,20 @@ class GitlabKeys # rubocop:disable Metrics/ClassLength ...@@ -9,12 +9,20 @@ class GitlabKeys # rubocop:disable Metrics/ClassLength
attr_accessor :auth_file, :key attr_accessor :auth_file, :key
def self.command(key_id) def self.command(whatever)
"#{ROOT_PATH}/bin/gitlab-shell #{whatever}"
end
def self.command_key(key_id)
unless /\A[a-z0-9-]+\z/ =~ key_id unless /\A[a-z0-9-]+\z/ =~ key_id
raise KeyError, "Invalid key_id: #{key_id.inspect}" raise KeyError, "Invalid key_id: #{key_id.inspect}"
end end
"#{ROOT_PATH}/bin/gitlab-shell #{key_id}" command(key_id)
end
def self.whatever_line(command, trailer)
"command=\"#{command}\",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty #{trailer}"
end end
def self.key_line(key_id, public_key) def self.key_line(key_id, public_key)
...@@ -24,7 +32,17 @@ class GitlabKeys # rubocop:disable Metrics/ClassLength ...@@ -24,7 +32,17 @@ class GitlabKeys # rubocop:disable Metrics/ClassLength
raise KeyError, "Invalid public_key: #{public_key.inspect}" raise KeyError, "Invalid public_key: #{public_key.inspect}"
end end
"command=\"#{command(key_id)}\",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty #{public_key}" whatever_line(command_key(key_id), public_key)
end
def self.principal_line(username_key_id, principal)
principal.chomp!
if principal.include?("\n")
raise KeyError, "Invalid principal: #{principal.inspect}"
end
whatever_line(command_key(username_key_id), principal)
end end
def initialize def initialize
...@@ -119,7 +137,7 @@ class GitlabKeys # rubocop:disable Metrics/ClassLength ...@@ -119,7 +137,7 @@ class GitlabKeys # rubocop:disable Metrics/ClassLength
$logger.info('Removing key', key_id: @key_id) $logger.info('Removing key', key_id: @key_id)
open_auth_file('r+') do |f| open_auth_file('r+') do |f|
while line = f.gets # rubocop:disable Style/AssignmentInCondition while line = f.gets # rubocop:disable Style/AssignmentInCondition
next unless line.start_with?("command=\"#{self.class.command(@key_id)}\"") next unless line.start_with?("command=\"#{self.class.command_key(@key_id)}\"")
f.seek(-line.length, IO::SEEK_CUR) f.seek(-line.length, IO::SEEK_CUR)
# Overwrite the line with #'s. Because the 'line' variable contains # Overwrite the line with #'s. Because the 'line' variable contains
# a terminating '\n', we write line.length - 1 '#' characters. # a terminating '\n', we write line.length - 1 '#' characters.
......
...@@ -26,22 +26,24 @@ class GitlabNet ...@@ -26,22 +26,24 @@ class GitlabNet
env: env env: env
} }
params[actor.class.identifier_key.to_sym] = actor.id params[actor.identifier_key.to_sym] = actor.id
resp = post("#{internal_api_endpoint}/allowed", params) resp = post("#{internal_api_endpoint}/allowed", params)
determine_action(actor, resp) determine_action(actor, resp)
end end
def discover(key_id) def discover(actor)
resp = get("#{internal_api_endpoint}/discover?key_id=#{key_id}") resp = get("#{internal_api_endpoint}/discover?#{actor.identifier_key}=#{actor.id}")
JSON.parse(resp.body) JSON.parse(resp.body)
rescue JSON::ParserError, ApiUnreachableError rescue JSON::ParserError, ApiUnreachableError
nil nil
end end
def lfs_authenticate(key_id, repo) def lfs_authenticate(actor, repo)
params = { project: sanitize_path(repo), key_id: key_id } params = { project: sanitize_path(repo) }
params[actor.identifier_key.to_sym] = actor.id
resp = post("#{internal_api_endpoint}/lfs_authenticate", params) resp = post("#{internal_api_endpoint}/lfs_authenticate", params)
GitlabLfsAuthentication.build_from_json(resp.body) if resp.code == HTTP_SUCCESS GitlabLfsAuthentication.build_from_json(resp.body) if resp.code == HTTP_SUCCESS
...@@ -75,8 +77,9 @@ class GitlabNet ...@@ -75,8 +77,9 @@ class GitlabNet
nil nil
end end
def two_factor_recovery_codes(key_id) def two_factor_recovery_codes(actor)
resp = post("#{internal_api_endpoint}/two_factor_recovery_codes", key_id: key_id) params = { actor.identifier_key.to_sym => actor.id }
resp = post("#{internal_api_endpoint}/two_factor_recovery_codes", params)
JSON.parse(resp.body) if resp.code == HTTP_SUCCESS JSON.parse(resp.body) if resp.code == HTTP_SUCCESS
rescue rescue
{} {}
......
...@@ -3,7 +3,7 @@ require 'pathname' ...@@ -3,7 +3,7 @@ require 'pathname'
require_relative 'gitlab_net' require_relative 'gitlab_net'
require_relative 'gitlab_metrics' require_relative 'gitlab_metrics'
require_relative 'actor/key' require_relative 'actor'
class GitlabShell class GitlabShell
API_2FA_RECOVERY_CODES_COMMAND = '2fa_recovery_codes'.freeze API_2FA_RECOVERY_CODES_COMMAND = '2fa_recovery_codes'.freeze
...@@ -18,9 +18,9 @@ class GitlabShell ...@@ -18,9 +18,9 @@ class GitlabShell
Struct.new('ParsedCommand', :command, :git_access_command, :repo_name, :args) Struct.new('ParsedCommand', :command, :git_access_command, :repo_name, :args)
def initialize(key_str) def initialize(who)
@key_str = key_str
@config = GitlabConfig.new @config = GitlabConfig.new
@actor = Actor.new_from(who, audit_usernames: @config.audit_usernames)
end end
# The origin_cmd variable contains UNTRUSTED input. If the user ran # The origin_cmd variable contains UNTRUSTED input. If the user ran
...@@ -28,22 +28,22 @@ class GitlabShell ...@@ -28,22 +28,22 @@ class GitlabShell
# 'evil command'. # 'evil command'.
def exec(origin_cmd) def exec(origin_cmd)
if !origin_cmd || origin_cmd.empty? if !origin_cmd || origin_cmd.empty?
puts "Welcome to GitLab, #{key.username}!" puts "Welcome to GitLab, #{actor.username}!"
return true return true
end end
parsed_command = parse_cmd(origin_cmd) parsed_command = parse_cmd(origin_cmd)
action = determine_action(parsed_command) action = determine_action(parsed_command) # FIXME: watch out
action.execute(parsed_command.command, parsed_command.args) action.execute(parsed_command.command, parsed_command.args)
rescue GitlabNet::ApiUnreachableError rescue GitlabNet::ApiUnreachableError
$stderr.puts "GitLab: Failed to authorize your Git request: internal API unreachable" $stderr.puts "GitLab: Failed to authorize your Git request: internal API unreachable"
false false
rescue AccessDeniedError, UnknownError => ex rescue AccessDeniedError, UnknownError => ex
$logger.warn('Access denied', command: origin_cmd, user: key.log_username) $logger.warn('Access denied', command: origin_cmd, user: actor.log_username)
$stderr.puts "GitLab: #{ex.message}" $stderr.puts "GitLab: #{ex.message}"
false false
rescue DisallowedCommandError rescue DisallowedCommandError
$logger.warn('Denied disallowed command', command: origin_cmd, user: key.log_username) $logger.warn('Denied disallowed command', command: origin_cmd, user: actor.log_username)
$stderr.puts 'GitLab: Disallowed command' $stderr.puts 'GitLab: Disallowed command'
false false
rescue InvalidRepositoryPathError rescue InvalidRepositoryPathError
...@@ -53,11 +53,7 @@ class GitlabShell ...@@ -53,11 +53,7 @@ class GitlabShell
private private
attr_reader :config, :key_str attr_reader :config, :actor
def key
@key ||= Actor::Key.from(key_str, audit_usernames: config.audit_usernames)
end
def parse_cmd(cmd) def parse_cmd(cmd)
args = Shellwords.shellwords(cmd) args = Shellwords.shellwords(cmd)
...@@ -99,7 +95,7 @@ class GitlabShell ...@@ -99,7 +95,7 @@ class GitlabShell
end end
def determine_action(parsed_command) def determine_action(parsed_command)
return Action::API2FARecovery.new(key) if parsed_command.command == API_2FA_RECOVERY_CODES_COMMAND return Action::API2FARecovery.new(actor) if parsed_command.command == API_2FA_RECOVERY_CODES_COMMAND
GitlabMetrics.measure('verify-access') do GitlabMetrics.measure('verify-access') do
# GitlatNet#check_access will raise exception in the event of a problem # GitlatNet#check_access will raise exception in the event of a problem
...@@ -107,13 +103,13 @@ class GitlabShell ...@@ -107,13 +103,13 @@ class GitlabShell
parsed_command.git_access_command, parsed_command.git_access_command,
nil, nil,
parsed_command.repo_name, parsed_command.repo_name,
key, actor,
'_any' '_any'
) )
case parsed_command.command case parsed_command.command
when GIT_LFS_AUTHENTICATE_COMMAND when GIT_LFS_AUTHENTICATE_COMMAND
Action::GitLFSAuthenticate.new(key, parsed_command.repo_name) Action::GitLFSAuthenticate.new(actor, parsed_command.repo_name)
else else
initial_action initial_action
end end
......
...@@ -3,18 +3,18 @@ require_relative '../../lib/action/api_2fa_recovery' ...@@ -3,18 +3,18 @@ require_relative '../../lib/action/api_2fa_recovery'
describe Action::API2FARecovery do describe Action::API2FARecovery do
let(:key_id) { '1' } let(:key_id) { '1' }
let(:key) { Actor::Key.new(key_id) } let(:actor) { Actor::Key.new(key_id) }
let(:username) { 'testuser' } let(:username) { 'testuser' }
let(:discover_payload) { { 'username' => username } } let(:discover_payload) { { 'username' => username } }
let(:api) { double(GitlabNet) } let(:api) { double(GitlabNet) }
before do before do
allow(GitlabNet).to receive(:new).and_return(api) allow(GitlabNet).to receive(:new).and_return(api)
allow(api).to receive(:discover).with(key_id).and_return(discover_payload) allow(api).to receive(:discover).with(actor).and_return(discover_payload)
end end
subject do subject do
described_class.new(key) described_class.new(actor)
end end
describe '#execute' do describe '#execute' do
...@@ -46,7 +46,7 @@ describe Action::API2FARecovery do ...@@ -46,7 +46,7 @@ describe Action::API2FARecovery do
before do before do
expect(subject).to receive(:continue?).and_return(true) expect(subject).to receive(:continue?).and_return(true)
expect(api).to receive(:two_factor_recovery_codes).with(key_id).and_return(response) expect(api).to receive(:two_factor_recovery_codes).with(subject).and_return(response)
end end
context 'with a unsuccessful response' do context 'with a unsuccessful response' do
......
...@@ -4,24 +4,24 @@ require_relative '../../lib/action/git_lfs_authenticate' ...@@ -4,24 +4,24 @@ require_relative '../../lib/action/git_lfs_authenticate'
describe Action::GitLFSAuthenticate do describe Action::GitLFSAuthenticate do
let(:key_id) { '1' } let(:key_id) { '1' }
let(:repo_name) { 'gitlab-ci.git' } let(:repo_name) { 'gitlab-ci.git' }
let(:key) { Actor::Key.new(key_id) } let(:actor) { Actor::Key.new(key_id) }
let(:username) { 'testuser' } let(:username) { 'testuser' }
let(:discover_payload) { { 'username' => username } } let(:discover_payload) { { 'username' => username } }
let(:api) { double(GitlabNet) } let(:api) { double(GitlabNet) }
before do before do
allow(GitlabNet).to receive(:new).and_return(api) allow(GitlabNet).to receive(:new).and_return(api)
allow(api).to receive(:discover).with(key_id).and_return(discover_payload) allow(api).to receive(:discover).with(actor).and_return(discover_payload)
end end
subject do subject do
described_class.new(key, repo_name) described_class.new(actor, repo_name)
end end
describe '#execute' do describe '#execute' do
context 'when response from API is not a success' do context 'when response from API is not a success' do
before do before do
expect(api).to receive(:lfs_authenticate).with(key_id, repo_name).and_return(nil) expect(api).to receive(:lfs_authenticate).with(subject, repo_name).and_return(nil)
end end
it 'returns nil' do it 'returns nil' do
...@@ -36,7 +36,7 @@ describe Action::GitLFSAuthenticate do ...@@ -36,7 +36,7 @@ describe Action::GitLFSAuthenticate do
let(:gitlab_lfs_authentication) { GitlabLfsAuthentication.new(username, lfs_token, repository_http_path) } let(:gitlab_lfs_authentication) { GitlabLfsAuthentication.new(username, lfs_token, repository_http_path) }
before do before do
expect(api).to receive(:lfs_authenticate).with(key_id, repo_name).and_return(gitlab_lfs_authentication) expect(api).to receive(:lfs_authenticate).with(subject, repo_name).and_return(gitlab_lfs_authentication)
end end
it 'puts payload to stdout' do it 'puts payload to stdout' do
......
...@@ -11,7 +11,7 @@ describe Actor::Key do ...@@ -11,7 +11,7 @@ describe Actor::Key do
before do before do
allow(GitlabNet).to receive(:new).and_return(api) allow(GitlabNet).to receive(:new).and_return(api)
allow(api).to receive(:discover).with(key_id).and_return(discover_payload) allow(api).to receive(:discover).with(subject).and_return(discover_payload)
end end
describe '.from' do describe '.from' do
......
...@@ -8,13 +8,25 @@ describe GitlabKeys do ...@@ -8,13 +8,25 @@ describe GitlabKeys do
end end
describe '.command' do describe '.command' do
it 'the internal "command" utility function' do
command = "#{ROOT_PATH}/bin/gitlab-shell does-not-validate"
expect(described_class.command('does-not-validate')).to eq(command)
end
it 'does not raise a KeyError on invalid input' do
command = "#{ROOT_PATH}/bin/gitlab-shell foo\nbar\nbaz\n"
expect(described_class.command("foo\nbar\nbaz\n")).to eq(command)
end
end
describe '.command_key' do
it 'returns the "command" part of the key line' do it 'returns the "command" part of the key line' do
command = "#{ROOT_PATH}/bin/gitlab-shell key-123" command = "#{ROOT_PATH}/bin/gitlab-shell key-123"
expect(described_class.command('key-123')).to eq(command) expect(described_class.command_key('key-123')).to eq(command)
end end
it 'raises KeyError on invalid input' do it 'raises KeyError on invalid input' do
expect do described_class.command("\nssh-rsa AAA") end.to raise_error(described_class::KeyError) expect { described_class.command_key("\nssh-rsa AAA") }.to raise_error(described_class::KeyError)
end end
end end
...@@ -30,7 +42,23 @@ describe GitlabKeys do ...@@ -30,7 +42,23 @@ describe GitlabKeys do
end end
it 'raises KeyError on invalid input' do it 'raises KeyError on invalid input' do
expect do described_class.key_line('key-741', "ssh-rsa AAA\nssh-rsa AAA") end.to raise_error(described_class::KeyError) expect { described_class.key_line('key-741', "ssh-rsa AAA\nssh-rsa AAA") }.to raise_error(described_class::KeyError)
end
end
describe '.principal_line' do
let(:line) { %(command="#{ROOT_PATH}/bin/gitlab-shell username-someuser",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty sshUsers) }
it 'returns the key line' do
expect(described_class.principal_line('username-someuser', 'sshUsers')).to eq(line)
end
it 'silently removes a trailing newline' do
expect(described_class.principal_line('username-someuser', "sshUsers\n")).to eq(line)
end
it 'raises KeyError on invalid input' do
expect { described_class.principal_line('username-someuser', "sshUsers\nloginUsers") }.to raise_error(described_class::KeyError)
end end
end end
......
This diff is collapsed.
...@@ -10,44 +10,44 @@ describe GitlabShell do ...@@ -10,44 +10,44 @@ describe GitlabShell do
after { FileUtils.rm_rf(tmp_repos_path) } after { FileUtils.rm_rf(tmp_repos_path) }
subject { described_class.new(key_id) } subject { described_class.new(who) }
let(:key_id) { '1' } let(:who) { 'key-1' }
let(:key) { Actor::Key.new(key_id) } let(:audit_usernames) { true }
let(:actor) { Actor.new_from(who, audit_usernames: audit_usernames) }
let(:tmp_repos_path) { File.join(ROOT_PATH, 'tmp', 'repositories') } let(:tmp_repos_path) { File.join(ROOT_PATH, 'tmp', 'repositories') }
let(:repo_name) { 'gitlab-ci.git' } let(:repo_name) { 'gitlab-ci.git' }
let(:repo_path) { File.join(tmp_repos_path, repo_name) } let(:repo_path) { File.join(tmp_repos_path, repo_name) }
let(:gl_repository) { 'project-1' } let(:gl_repository) { 'project-1' }
let(:gl_username) { 'testuser' } let(:gl_username) { 'testuser' }
let(:audit_usernames) { true }
let(:api) { double(GitlabNet) } let(:api) { double(GitlabNet) }
let(:config) { double(GitlabConfig) } let(:config) { double(GitlabConfig) }
let(:gitaly_action) { Action::Gitaly.new( let(:gitaly_action) { Action::Gitaly.new(
key_id, actor,
gl_repository, gl_repository,
gl_username, gl_username,
repo_path, repo_path,
{ 'repository' => { 'relative_path' => repo_name, 'storage_name' => 'default' } , 'address' => 'unix:gitaly.socket' }) { 'repository' => { 'relative_path' => repo_name, 'storage_name' => 'default' } , 'address' => 'unix:gitaly.socket' })
} }
let(:api_2fa_recovery_action) { Action::API2FARecovery.new(key_id) } let(:api_2fa_recovery_action) { Action::API2FARecovery.new(actor) }
let(:git_lfs_authenticate_action) { Action::GitLFSAuthenticate.new(key_id, repo_name) } let(:git_lfs_authenticate_action) { Action::GitLFSAuthenticate.new(actor, repo_name) }
before do before do
allow(GitlabConfig).to receive(:new).and_return(config) allow(GitlabConfig).to receive(:new).and_return(config)
allow(config).to receive(:audit_usernames).and_return(audit_usernames) allow(config).to receive(:audit_usernames).and_return(audit_usernames)
allow(Actor::Key).to receive(:from).with(key_id, audit_usernames: audit_usernames).and_return(key) allow(Actor).to receive(:new_from).with(who, audit_usernames: audit_usernames).and_return(actor)
allow(GitlabNet).to receive(:new).and_return(api) allow(GitlabNet).to receive(:new).and_return(api)
allow(api).to receive(:discover).with(key_id).and_return('username' => gl_username) allow(api).to receive(:discover).with(actor).and_return('username' => gl_username)
end end
describe '#exec' do describe '#exec' do
context "when we don't have a valid user" do context "when we don't have a valid user" do
before do before do
allow(api).to receive(:discover).with(key_id).and_return(nil) allow(api).to receive(:discover).with(actor).and_return(nil)
end end
it 'prints Welcome.. and returns true' do it 'prints Welcome.. and returns true' do
...@@ -114,7 +114,7 @@ describe GitlabShell do ...@@ -114,7 +114,7 @@ describe GitlabShell do
let(:git_access) { '2fa_recovery_codes' } let(:git_access) { '2fa_recovery_codes' }
before do before do
expect(Action::API2FARecovery).to receive(:new).with(key).and_return(api_2fa_recovery_action) expect(Action::API2FARecovery).to receive(:new).with(actor).and_return(api_2fa_recovery_action)
end end
it 'returns true' do it 'returns true' do
...@@ -125,7 +125,7 @@ describe GitlabShell do ...@@ -125,7 +125,7 @@ describe GitlabShell do
context 'when access to the repo is denied' do context 'when access to the repo is denied' do
before do before do
expect(api).to receive(:check_access).with('git-upload-pack', nil, repo_name, key, '_any').and_raise(AccessDeniedError, 'Sorry, access denied') expect(api).to receive(:check_access).with('git-upload-pack', nil, repo_name, actor, '_any').and_raise(AccessDeniedError, 'Sorry, access denied')
end end
it 'prints a message to stderr and returns false' do it 'prints a message to stderr and returns false' do
...@@ -136,7 +136,7 @@ describe GitlabShell do ...@@ -136,7 +136,7 @@ describe GitlabShell do
context 'when the API is unavailable' do context 'when the API is unavailable' do
before do before do
expect(api).to receive(:check_access).with('git-upload-pack', nil, repo_name, key, '_any').and_raise(GitlabNet::ApiUnreachableError) expect(api).to receive(:check_access).with('git-upload-pack', nil, repo_name, actor, '_any').and_raise(GitlabNet::ApiUnreachableError)
end end
it 'prints a message to stderr and returns false' do it 'prints a message to stderr and returns false' do
...@@ -147,7 +147,7 @@ describe GitlabShell do ...@@ -147,7 +147,7 @@ describe GitlabShell do
context 'when access has been verified OK' do context 'when access has been verified OK' do
before do before do
expect(api).to receive(:check_access).with(git_access, nil, repo_name, key, '_any').and_return(gitaly_action) expect(api).to receive(:check_access).with(git_access, nil, repo_name, actor, '_any').and_return(gitaly_action)
end end
context 'when origin_cmd is git-upload-pack' do context 'when origin_cmd is git-upload-pack' do
...@@ -180,7 +180,7 @@ describe GitlabShell do ...@@ -180,7 +180,7 @@ describe GitlabShell do
let(:lfs_access) { double(GitlabLfsAuthentication, authentication_payload: fake_payload)} let(:lfs_access) { double(GitlabLfsAuthentication, authentication_payload: fake_payload)}
before do before do
expect(Action::GitLFSAuthenticate).to receive(:new).with(key, repo_name).and_return(git_lfs_authenticate_action) expect(Action::GitLFSAuthenticate).to receive(:new).with(actor, repo_name).and_return(git_lfs_authenticate_action)
end end
context 'upload' do context 'upload' 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