Move SMB credentials validation into host capability

This commit is contained in:
Chris Roberts 2018-01-12 16:43:19 -08:00
parent 01bc2627be
commit 5444271268
6 changed files with 65 additions and 21 deletions

View File

@ -17,6 +17,16 @@ module VagrantPlugins
true true
end end
def self.smb_validate_password(env, machine, username, password)
script_path = File.expand_path("../../scripts/check_credentials.ps1", __FILE__)
args = []
args << "-username" << "'#{username.gsub("'", "''")}'"
args << "-password" << "'#{password.gsub("'", "''")}'"
r = Vagrant::Util::PowerShell.execute(script_path, *args)
r.exit_code == 0
end
def self.smb_cleanup(env, machine, opts) def self.smb_cleanup(env, machine, opts)
script_path = File.expand_path("../../scripts/unset_share.ps1", __FILE__) script_path = File.expand_path("../../scripts/unset_share.ps1", __FILE__)

View File

@ -46,6 +46,11 @@ module VagrantPlugins
Cap::SMB Cap::SMB
end end
host_capability("windows", "smb_cleanup") do
require_relative "cap/smb"
Cap::SMB
end
host_capability("windows", "configured_ip_addresses") do host_capability("windows", "configured_ip_addresses") do
require_relative "cap/configured_ip_addresses" require_relative "cap/configured_ip_addresses"
Cap::ConfiguredIPAddresses Cap::ConfiguredIPAddresses

View File

@ -26,6 +26,10 @@ module VagrantPlugins
error_key(:name_error) error_key(:name_error)
end end
class CredentialsRequestError < SMBError
error_key(:credentials_request_error)
end
class DefineShareFailed < SMBError class DefineShareFailed < SMBError
error_key(:define_share_failed) error_key(:define_share_failed)
end end

View File

@ -11,6 +11,10 @@ require_relative "errors"
module VagrantPlugins module VagrantPlugins
module SyncedFolderSMB module SyncedFolderSMB
class SyncedFolder < Vagrant.plugin("2", :synced_folder) class SyncedFolder < Vagrant.plugin("2", :synced_folder)
# Maximum number of times to retry requesting username/password
CREDENTIAL_RETRY_MAX = 5
def initialize(*args) def initialize(*args)
super super
@ -43,28 +47,27 @@ module VagrantPlugins
end end
end end
script_path = File.expand_path("../scripts/check_credentials.ps1", __FILE__)
if !have_auth if !have_auth
machine.ui.detail(I18n.t("vagrant_sf_smb.warning_password") + "\n ") machine.ui.detail(I18n.t("vagrant_sf_smb.warning_password") + "\n ")
auth_success = false retries = 0
while !auth_success do while retries < CREDENTIAL_RETRY_MAX do
@creds[:username] = machine.ui.ask("Username: ") smb_username = machine.ui.ask("Username: ")
@creds[:password] = machine.ui.ask("Password (will be hidden): ", echo: false) smb_password = machine.ui.ask("Password (will be hidden): ", echo: false)
auth_success = true
args = [] if machine.env.host.capability?(:smb_validate_password)
args << "-username" << "'#{@creds[:username].gsub("'", "''")}'" Vagrant::Util::CredentialScrubber.sensitive(smb_password)
args << "-password" << "'#{@creds[:password].gsub("'", "''")}'" auth_success = machine.env.host.capability(:smb_validate_password,
smb_username, smb_password)
r = Vagrant::Util::PowerShell.execute(script_path, *args)
if r.exit_code == 0
auth_success = true
end end
if !auth_success break if auth_success
machine.ui.output(I18n.t("vagrant_sf_smb.incorrect_credentials") + "\n ") machine.ui.output(I18n.t("vagrant_sf_smb.incorrect_credentials") + "\n ")
end retries += 1
end
if retries >= CREDENTIAL_RETRY_MAX
raise Errors::CredentialsRequestError
end end
end end
@ -73,8 +76,6 @@ module VagrantPlugins
machine.env.host.capability(:smb_start) machine.env.host.capability(:smb_start)
end end
script_path = File.expand_path("../scripts/set_share.ps1", __FILE__)
folders.each do |id, data| folders.each do |id, data|
data[:smb_username] ||= smb_username data[:smb_username] ||= smb_username
data[:smb_password] ||= smb_password data[:smb_password] ||= smb_password

View File

@ -39,6 +39,9 @@ en:
Vagrant SMB synced folders require the account password to be stored Vagrant SMB synced folders require the account password to be stored
in an NT compatible format. Please update your sharing settings to in an NT compatible format. Please update your sharing settings to
enable a Windows compatible password and try again. enable a Windows compatible password and try again.
credentials_request_error: |-
Vagrant failed to receive credential information required for preparing
an SMB share.
define_share_failed: |- define_share_failed: |-
Exporting an SMB share failed! Details about the failure are shown Exporting an SMB share failed! Details about the failure are shown
below. Please inspect the error message and correct any problems. below. Please inspect the error message and correct any problems.

View File

@ -71,8 +71,8 @@ describe VagrantPlugins::SyncedFolderSMB::SyncedFolder do
context "without credentials provided" do context "without credentials provided" do
before do before do
expect(machine.env.ui).to receive(:ask).and_return('username') expect(machine.env.ui).to receive(:ask).with(/name/, any_args).and_return('username').at_least(1)
expect(machine.env.ui).to receive(:ask).and_return('password') expect(machine.env.ui).to receive(:ask).with(/word/, any_args).and_return('password').at_least(1)
end end
it "should prompt for credentials" do it "should prompt for credentials" do
@ -91,6 +91,27 @@ describe VagrantPlugins::SyncedFolderSMB::SyncedFolder do
expect(host).to receive(:capability).with(:smb_start, any_args) expect(host).to receive(:capability).with(:smb_start, any_args)
subject.prepare(machine, folders, options) subject.prepare(machine, folders, options)
end end
context "with host smb_validate_password capability" do
let(:host_caps){ [:smb_start, :smb_prepare, :smb_validate_password] }
it "should validate the password" do
expect(host).to receive(:capability).with(:smb_validate_password, 'username', 'password').and_return(true)
subject.prepare(machine, folders, options)
end
it "should retry when validation fails" do
expect(host).to receive(:capability).with(:smb_validate_password, 'username', 'password').and_return(false)
expect(host).to receive(:capability).with(:smb_validate_password, 'username', 'password').and_return(true)
subject.prepare(machine, folders, options)
end
it "should raise an error if it exceeds the maximum number of retries" do
expect(host).to receive(:capability).with(:smb_validate_password, 'username', 'password').and_return(false).
exactly(VagrantPlugins::SyncedFolderSMB::SyncedFolder::CREDENTIAL_RETRY_MAX).times
expect{ subject.prepare(machine, folders, options) }.to raise_error(VagrantPlugins::SyncedFolderSMB::Errors::CredentialsRequestError)
end
end
end end
context "with credentials provided" do context "with credentials provided" do