summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorÆvar Arnfjörð Bjarmason <avarab@gmail.com>2018-06-14 15:54:38 +0200
committerÆvar Arnfjörð Bjarmason <avarab@gmail.com>2018-07-26 12:35:55 +0200
commit2e8b67027067761034f36dadb3c2208ce66d2552 (patch)
tree1f35c43611dcd0041d3f30fe7a86eac507912b75 /spec
parentdc67cf1a62529bf7aecc8e350994ac40d5f4a068 (diff)
downloadgitlab-shell-2e8b67027067761034f36dadb3c2208ce66d2552.tar.gz
Add support for SSH certificate authentication
This along with the code submitted to gitlab-ce in the gitlab-org/gitlab-ce! MR implements SSH certificate authentication. See the docs added to gitlab-ce for why and how to enable this. This, along with that MR, closes gitlab-org/gitlab-ce#3457 Implementation notes: - Because it's easy to do, and because an earlier nascent version of this would pass user-ID to gitlab-shell, that's now supported, even though the SSH certificate authentication uses username-USERNAME. - The astute reader will notice that not all the API calls in gitlab-ce's lib/api/internal.rb support a "username" argument, some only support "user_id". There's a few reasons for this: a) For this to be efficient, I am bending over backwards to avoid extra API calls when using SSH certificates. Therefore the /allowed API call will now return a "user id" to us if we're allowed to proceed further. This is then fed to existing APIs that would only be called after a successful call to /allowed. b) Not all of the git-shell codepaths go through /internal/allowed, or ever deal with a repository, e.g. the argument-less "Welcome to GitLab", and /internal/2fa_recovery_codes. These need to use /internal/discover to figure out details about the user, so support looking that up by username. c) Once we have the "user id", the GL_ID gets passed down to e.g. user-authored hooks. I don't want to have those all break by having to handle a third GL_ID mode of "username" in addition to the current "key id" and "user id".
Diffstat (limited to 'spec')
-rw-r--r--spec/gitlab_access_spec.rb2
-rw-r--r--spec/gitlab_keys_spec.rb32
-rw-r--r--spec/gitlab_shell_spec.rb38
3 files changed, 53 insertions, 19 deletions
diff --git a/spec/gitlab_access_spec.rb b/spec/gitlab_access_spec.rb
index 8882e01..d082176 100644
--- a/spec/gitlab_access_spec.rb
+++ b/spec/gitlab_access_spec.rb
@@ -10,6 +10,7 @@ describe GitlabAccess do
api.stub(check_access: GitAccessStatus.new(true,
'ok',
gl_repository: 'project-1',
+ gl_id: 'user-123',
gl_username: 'testuser',
repository_path: '/home/git/repositories',
gitaly: nil))
@@ -47,6 +48,7 @@ describe GitlabAccess do
false,
'denied',
gl_repository: nil,
+ gl_id: nil,
gl_username: nil,
repository_path: nil,
gitaly: nil
diff --git a/spec/gitlab_keys_spec.rb b/spec/gitlab_keys_spec.rb
index d6583b8..7011ca0 100644
--- a/spec/gitlab_keys_spec.rb
+++ b/spec/gitlab_keys_spec.rb
@@ -8,13 +8,25 @@ describe GitlabKeys do
end
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
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
it 'raises KeyError on invalid input' do
- expect { described_class.command("\nssh-rsa AAA") }.to raise_error(described_class::KeyError)
+ expect { described_class.command_key("\nssh-rsa AAA") }.to raise_error(described_class::KeyError)
end
end
@@ -34,6 +46,22 @@ describe GitlabKeys do
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
+
describe :initialize do
let(:gitlab_keys) { build_gitlab_keys('add-key', 'key-741', 'ssh-rsa AAAAB3NzaDAxx2E') }
diff --git a/spec/gitlab_shell_spec.rb b/spec/gitlab_shell_spec.rb
index af84b29..3f7c962 100644
--- a/spec/gitlab_shell_spec.rb
+++ b/spec/gitlab_shell_spec.rb
@@ -13,8 +13,8 @@ describe GitlabShell do
end
subject do
- ARGV[0] = key_id
- GitlabShell.new(key_id).tap do |shell|
+ ARGV[0] = gl_id
+ GitlabShell.new(gl_id).tap do |shell|
shell.stub(exec_cmd: :exec_called)
shell.stub(api: api)
end
@@ -24,6 +24,7 @@ describe GitlabShell do
true,
'ok',
gl_repository: gl_repository,
+ gl_id: gl_id,
gl_username: gl_username,
repository_path: repo_path,
gitaly: { 'repository' => { 'relative_path' => repo_name, 'storage_name' => 'default'} , 'address' => 'unix:gitaly.socket' }
@@ -37,6 +38,7 @@ describe GitlabShell do
true,
'ok',
gl_repository: gl_repository,
+ gl_id: gl_id,
gl_username: gl_username,
repository_path: repo_path,
gitaly: nil))
@@ -47,13 +49,14 @@ describe GitlabShell do
end
end
- let(:key_id) { "key-#{rand(100) + 100}" }
+ let(:gl_id) { "key-#{rand(100) + 100}" }
let(:ssh_cmd) { nil }
let(:tmp_repos_path) { File.join(ROOT_PATH, 'tmp', 'repositories') }
let(:repo_name) { 'gitlab-ci.git' }
let(:repo_path) { File.join(tmp_repos_path, repo_name) }
let(:gl_repository) { 'project-1' }
+ let(:gl_id) { 'user-1' }
let(:gl_username) { 'testuser' }
before do
@@ -63,7 +66,7 @@ describe GitlabShell do
describe :initialize do
let(:ssh_cmd) { 'git-receive-pack' }
- its(:key_id) { should == key_id }
+ its(:gl_id) { should == gl_id }
end
describe :parse_cmd do
@@ -146,7 +149,7 @@ describe GitlabShell do
end
describe :exec do
- let(:gitaly_message) { JSON.dump({ 'repository' => { 'relative_path' => repo_name, 'storage_name' => 'default' }, 'gl_repository' => gl_repository, 'gl_id' => key_id, 'gl_username' => gl_username}) }
+ let(:gitaly_message) { JSON.dump({ 'repository' => { 'relative_path' => repo_name, 'storage_name' => 'default' }, 'gl_repository' => gl_repository, 'gl_id' => gl_id, 'gl_username' => gl_username}) }
shared_examples_for 'upload-pack' do |command|
let(:ssh_cmd) { "#{command} gitlab-ci.git" }
@@ -162,7 +165,7 @@ describe GitlabShell do
it "should log the command execution" do
message = "executing git command"
- user_string = "user with key #{key_id}"
+ user_string = "user with id #{gl_id}"
$logger.should_receive(:info).with(message, command: "git-upload-pack #{repo_path}", user: user_string)
end
@@ -197,7 +200,7 @@ describe GitlabShell do
it "should log the command execution" do
message = "executing git command"
- user_string = "user with key #{key_id}"
+ user_string = "user with id #{gl_id}"
$logger.should_receive(:info).with(message, command: "gitaly-upload-pack unix:gitaly.socket #{gitaly_message}", user: user_string)
end
@@ -221,7 +224,7 @@ describe GitlabShell do
it "should log the command execution" do
message = "executing git command"
- user_string = "user with key #{key_id}"
+ user_string = "user with id #{gl_id}"
$logger.should_receive(:info).with(message, command: "git-receive-pack #{repo_path}", user: user_string)
end
end
@@ -243,7 +246,7 @@ describe GitlabShell do
it "should log the command execution" do
message = "executing git command"
- user_string = "user with key #{key_id}"
+ user_string = "user with id #{gl_id}"
$logger.should_receive(:info).with(message, command: "gitaly-receive-pack unix:gitaly.socket #{gitaly_message}", user: user_string)
end
@@ -270,7 +273,7 @@ describe GitlabShell do
it "should log the command execution" do
message = "executing git command"
- user_string = "user with key #{key_id}"
+ user_string = "user with id #{gl_id}"
$logger.should_receive(:info).with(message, command: exec_cmd_log_params.join(' '), user: user_string)
end
@@ -322,7 +325,7 @@ describe GitlabShell do
it "should log the attempt" do
message = 'Denied disallowed command'
- user_string = "user with key #{key_id}"
+ user_string = "user with id #{gl_id}"
$logger.should_receive(:warn).with(message, command: 'arbitrary command', user: user_string)
end
end
@@ -331,7 +334,7 @@ describe GitlabShell do
after { subject.exec(nil) }
it "should call api.discover" do
- api.should_receive(:discover).with(key_id)
+ api.should_receive(:discover).with(gl_id)
end
end
@@ -398,7 +401,7 @@ describe GitlabShell do
after { subject.exec(ssh_cmd) }
it "should call api.check_access" do
- api.should_receive(:check_access).with('git-upload-pack', nil, 'gitlab-ci.git', key_id, '_any', 'ssh')
+ api.should_receive(:check_access).with('git-upload-pack', nil, 'gitlab-ci.git', gl_id, '_any', 'ssh')
end
it "should disallow access and log the attempt if check_access returns false status" do
@@ -406,11 +409,12 @@ describe GitlabShell do
false,
'denied',
gl_repository: nil,
+ gl_id: nil,
gl_username: nil,
repository_path: nil,
gitaly: nil))
message = 'Access denied'
- user_string = "user with key #{key_id}"
+ user_string = "user with id #{gl_id}"
$logger.should_receive(:warn).with(message, command: 'git-upload-pack gitlab-ci.git', user: user_string)
end
end
@@ -436,14 +440,14 @@ describe GitlabShell do
end
describe :exec_cmd do
- let(:shell) { GitlabShell.new(key_id) }
+ let(:shell) { GitlabShell.new(gl_id) }
let(:env) do
{
'HOME' => ENV['HOME'],
'PATH' => ENV['PATH'],
'LD_LIBRARY_PATH' => ENV['LD_LIBRARY_PATH'],
'LANG' => ENV['LANG'],
- 'GL_ID' => key_id,
+ 'GL_ID' => gl_id,
'GL_PROTOCOL' => 'ssh',
'GL_REPOSITORY' => gl_repository,
'GL_USERNAME' => 'testuser'
@@ -543,7 +547,7 @@ describe GitlabShell do
end
describe :api do
- let(:shell) { GitlabShell.new(key_id) }
+ let(:shell) { GitlabShell.new(gl_id) }
subject { shell.send :api }
it { should be_a(GitlabNet) }