Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Try to use ssh agent if no password or key files have been specified #165

Merged
merged 1 commit into from
Nov 29, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ end

group :tools do
gem 'pry', '~> 0.10'
gem 'rb-readline'
gem 'license_finder'
gem 'github_changelog_generator', '~> 1'
end
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@ train = Train.create('ssh',
host: '1.2.3.4', port: 22, user: 'root', key_files: '/vagrant')
```

If you don't specify the `key_files` and `password` options, SSH agent authentication will be attempted. For example:

```ruby
require 'train'
train = Train.create('ssh', host: '1.2.3.4', port: 22, user: 'root')
```

**WinRM**

```ruby
Expand Down
28 changes: 22 additions & 6 deletions lib/train/transports/ssh.rb
Original file line number Diff line number Diff line change
Expand Up @@ -82,12 +82,6 @@ def validate_options(options)
super(options)

key_files = Array(options[:key_files])
if key_files.empty? and options[:password].nil?
fail Train::ClientError,
'You must configure at least one authentication method for SSH:'\
' Password or key.'
end

options[:auth_methods] ||= ['none']

unless key_files.empty?
Expand All @@ -100,6 +94,17 @@ def validate_options(options)
options[:auth_methods].push('password', 'keyboard-interactive')
end

if options[:auth_methods] == ['none']
if ssh_known_identities.empty?
fail Train::ClientError,
'You must configure at least one authentication method for SSH:'\
' Agent, Key or Password.'
else
logger.debug('[SSH] Using Agent keys as no password or key file have been specified')
options[:auth_methods].push('publickey')
end
end

if options[:pty]
logger.warn('[SSH] PTY requested: stderr will be merged into stdout')
end
Expand All @@ -108,6 +113,17 @@ def validate_options(options)
self
end

# Creates an SSH Authentication KeyManager instance and saves it for
# potential future reuse.
#
# @return [Hash] hash of SSH Known Identities
# @api private
def ssh_known_identities
# Force KeyManager to load the key(s)
@manager ||= Net::SSH::Authentication::KeyManager.new(nil).each_identity {}
@manager.known_identities
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This 3-liner could be simplified to:

@manager ||= Net::SSH...blah
@manager.known_identities

DRY 😉

end

# Builds the hash of options needed by the Connection object on
# construction.
#
Expand Down
26 changes: 23 additions & 3 deletions test/unit/transports/ssh_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ def detect_family
password: rand.to_s,
key_files: rand.to_s,
}}
let(:cls_agent) { cls.new({ host: rand.to_s }) }

describe 'default options' do
let(:ssh) { cls.new({ host: 'dummy' }) }
Expand Down Expand Up @@ -84,6 +85,26 @@ def detect_family
"root@#{conf[:host]}",
])
end

it 'sets the right auth_methods when password is specified' do
conf[:key_files] = nil
cls.new(conf).connection.method(:options).call[:auth_methods].must_equal ["none", "password", "keyboard-interactive"]
end

it 'sets the right auth_methods when keys are specified' do
conf[:password] = nil
cls.new(conf).connection.method(:options).call[:auth_methods].must_equal ["none", "publickey"]
end

it 'sets the right auth_methods for agent auth' do
cls_agent.stubs(:ssh_known_identities).returns({:some => 'rsa_key'})
cls_agent.connection.method(:options).call[:auth_methods].must_equal ['none', 'publickey']
end

it 'works with ssh agent auth' do
cls_agent.stubs(:ssh_known_identities).returns({:some => 'rsa_key'})
cls_agent.connection
end
end

describe 'converting connection to string for logging' do
Expand Down Expand Up @@ -111,9 +132,8 @@ def detect_family
end

it 'does not like key and password == nil' do
conf.delete(:password)
conf.delete(:key_files)
proc { cls.new(conf).connection }.must_raise Train::ClientError
cls_agent.stubs(:ssh_known_identities).returns({})
proc { cls_agent.connection }.must_raise Train::ClientError
end

it 'wont connect if it is not possible' do
Expand Down