Merge pull request #4670 from gildegoma/dry-check-ssh-perms

Check SSH key permissions in machine.ssh_info
This commit is contained in:
Mitchell Hashimoto 2014-10-23 09:14:31 -07:00
commit 381f1332c8
6 changed files with 62 additions and 39 deletions

View File

@ -31,11 +31,6 @@ module Vagrant
info[:private_key_path] ||= [] info[:private_key_path] ||= []
# Check SSH key permissions
info[:private_key_path].each do |path|
SSH.check_key_permissions(Pathname.new(path))
end
if info[:private_key_path].empty? && info[:password] if info[:private_key_path].empty? && info[:password]
env[:ui].warn(I18n.t("vagrant.ssh_exec_password")) env[:ui].warn(I18n.t("vagrant.ssh_exec_password"))
end end

View File

@ -29,11 +29,6 @@ module Vagrant
info[:private_key_path] ||= [] info[:private_key_path] ||= []
# Check SSH key permissions
info[:private_key_path].each do |path|
SSH.check_key_permissions(Pathname.new(path))
end
if info[:private_key_path].empty? if info[:private_key_path].empty?
raise Errors::SSHRunRequiresKeys raise Errors::SSHRunRequiresKeys
end end

View File

@ -1,3 +1,5 @@
require_relative "util/ssh"
require "digest/md5" require "digest/md5"
require "thread" require "thread"
@ -70,6 +72,12 @@ module Vagrant
# @return [Vagrantfile] # @return [Vagrantfile]
attr_reader :vagrantfile attr_reader :vagrantfile
# The SSH information for accessing this machine.
# This attribute is set only when the machine is ready for SSH communication.
#
# @return [Hash]
attr_reader :ssh_info
# Initialize a new machine. # Initialize a new machine.
# #
# @param [String] name Name of the virtual machine. # @param [String] name Name of the virtual machine.
@ -383,6 +391,9 @@ module Vagrant
# #
# @return [Hash] SSH information. # @return [Hash] SSH information.
def ssh_info def ssh_info
return @ssh_info unless @ssh_info.nil?
# First, ask the provider for their information. If the provider # First, ask the provider for their information. If the provider
# returns nil, then the machine is simply not ready for SSH, and # returns nil, then the machine is simply not ready for SSH, and
# we return nil as well. # we return nil as well.
@ -442,8 +453,16 @@ module Vagrant
File.expand_path(path, @env.root_path) File.expand_path(path, @env.root_path)
end end
# Return the final compiled SSH info data # Check that the private key permissions are valid
info info[:private_key_path].each do |path|
key_path = Pathname.new(path)
if key_path.exist?
Vagrant::Util::SSH.check_key_permissions(key_path)
end
end
# Memoize the final compiled SSH info data and return it
@ssh_info = info
end end
# Returns the state of this machine. The state is queried from the # Returns the state of this machine. The state is queried from the

View File

@ -13,7 +13,6 @@ require 'vagrant/util/ansi_escape_code_remover'
require 'vagrant/util/file_mode' require 'vagrant/util/file_mode'
require 'vagrant/util/platform' require 'vagrant/util/platform'
require 'vagrant/util/retryable' require 'vagrant/util/retryable'
require 'vagrant/util/ssh'
module VagrantPlugins module VagrantPlugins
module CommunicatorSSH module CommunicatorSSH
@ -314,11 +313,6 @@ module VagrantPlugins
verbose: :debug, verbose: :debug,
} }
# Check that the private key permissions are valid
ssh_info[:private_key_path].each do |path|
Vagrant::Util::SSH.check_key_permissions(Pathname.new(path))
end
# Connect to SSH, giving it a few tries # Connect to SSH, giving it a few tries
connection = nil connection = nil
begin begin

View File

@ -1,7 +1,5 @@
require File.expand_path("../../../../base", __FILE__) require File.expand_path("../../../../base", __FILE__)
require "vagrant/util/ssh"
describe Vagrant::Action::Builtin::SSHExec do describe Vagrant::Action::Builtin::SSHExec do
let(:app) { lambda { |env| } } let(:app) { lambda { |env| } }
let(:env) { { machine: machine } } let(:env) { { machine: machine } }
@ -16,7 +14,6 @@ describe Vagrant::Action::Builtin::SSHExec do
before(:each) do before(:each) do
# Stub the methods so that even if we test incorrectly, no side # Stub the methods so that even if we test incorrectly, no side
# effects actually happen. # effects actually happen.
allow(ssh_klass).to receive(:check_key_permissions)
allow(ssh_klass).to receive(:exec) allow(ssh_klass).to receive(:exec)
end end
@ -29,23 +26,6 @@ describe Vagrant::Action::Builtin::SSHExec do
to raise_error(Vagrant::Errors::SSHNotReady) to raise_error(Vagrant::Errors::SSHNotReady)
end end
it "should check key permissions then exec" do
key_path = "/foo"
machine_ssh_info[:private_key_path] = [key_path]
expect(ssh_klass).to receive(:check_key_permissions).
with(Pathname.new(key_path)).
once.
ordered
expect(ssh_klass).to receive(:exec).
with(machine_ssh_info, nil).
once.
ordered
described_class.new(app, env).call(env)
end
it "should exec with the SSH info in the env if given" do it "should exec with the SSH info in the env if given" do
ssh_info = { foo: :bar } ssh_info = { foo: :bar }

View File

@ -473,7 +473,8 @@ describe Vagrant::Machine do
end end
end end
describe "ssh info" do describe "#ssh_info" do
describe "with the provider returning nil" do describe "with the provider returning nil" do
it "should return nil if the provider returns nil" do it "should return nil if the provider returns nil" do
expect(provider).to receive(:ssh_info).and_return(nil) expect(provider).to receive(:ssh_info).and_return(nil)
@ -483,9 +484,13 @@ describe Vagrant::Machine do
describe "with the provider returning data" do describe "with the provider returning data" do
let(:provider_ssh_info) { {} } let(:provider_ssh_info) { {} }
let(:ssh_klass) { Vagrant::Util::SSH }
before(:each) do before(:each) do
allow(provider).to receive(:ssh_info).and_return(provider_ssh_info) allow(provider).to receive(:ssh_info).and_return(provider_ssh_info)
# Stub the check_key_permissions method so that even if we test incorrectly,
# no side effects actually happen.
allow(ssh_klass).to receive(:check_key_permissions)
end end
[:host, :port, :username].each do |type| [:host, :port, :username].each do |type|
@ -557,6 +562,41 @@ describe Vagrant::Machine do
]) ])
end end
it "should check and try to fix the permissions of the default private key file" do
provider_ssh_info[:private_key_path] = nil
instance.config.ssh.private_key_path = nil
expect(ssh_klass).to receive(:check_key_permissions).once.with(Pathname.new(instance.env.default_private_key_path.to_s))
instance.ssh_info
end
it "should check and try to fix the permissions of given private key files" do
provider_ssh_info[:private_key_path] = nil
# Use __FILE__ to provide an existing file
instance.config.ssh.private_key_path = [File.expand_path(__FILE__), File.expand_path(__FILE__)]
expect(ssh_klass).to receive(:check_key_permissions).twice.with(Pathname.new(File.expand_path(__FILE__)))
instance.ssh_info
end
it "should not check the permissions of a private key file that does not exist" do
provider_ssh_info[:private_key_path] = "/foo"
expect(ssh_klass).to_not receive(:check_key_permissions)
instance.ssh_info
end
# It is not possible to test the memoization of a Ruby Hash with object equality,
# but we can verify that some code of ssh_info method is not executed again.
it "should check and try to fix the permissions of the private key file only once" do
provider_ssh_info[:private_key_path] = nil
instance.config.ssh.private_key_path = nil
expect(ssh_klass).to receive(:check_key_permissions).once.with(Pathname.new(instance.env.default_private_key_path.to_s))
instance.ssh_info
instance.ssh_info
end
context "expanding path relative to the root path" do context "expanding path relative to the root path" do
it "should with the provider key path" do it "should with the provider key path" do
provider_ssh_info[:private_key_path] = "~/foo" provider_ssh_info[:private_key_path] = "~/foo"