diff options
-rw-r--r-- | lib/chef/mixin/user_context.rb | 8 | ||||
-rw-r--r-- | lib/chef/provider/remote_file/network_file.rb | 2 | ||||
-rw-r--r-- | lib/chef/resource/remote_file.rb | 2 | ||||
-rw-r--r-- | lib/chef/util/windows/logon_session.rb | 10 | ||||
-rw-r--r-- | spec/functional/win32/security_spec.rb | 1 | ||||
-rw-r--r-- | spec/unit/util/windows/logon_session_spec.rb | 4 | ||||
-rw-r--r-- | spec/unit/win32/security_spec.rb | 36 |
7 files changed, 52 insertions, 11 deletions
diff --git a/lib/chef/mixin/user_context.rb b/lib/chef/mixin/user_context.rb index 0807bd5a95..f5c2da1389 100644 --- a/lib/chef/mixin/user_context.rb +++ b/lib/chef/mixin/user_context.rb @@ -22,8 +22,10 @@ class Chef module Mixin module UserContext - # valid logon_type values => :remote, :local - def with_user_context(user, password, domain = nil, logon_type = :remote, &block) + # valid values for authentication => :remote, :local + # When authentication = :local, we use the credentials to create a logon session against the local system, and then try to access the files. + # When authentication = :remote, we continue with the current user but pass the provided credentials to the remote system. + def with_user_context(user, password, domain = nil, authentication = :remote, &block) unless Chef::Platform.windows? raise Exceptions::UnsupportedPlatform, "User context impersonation is supported only on the Windows platform" end @@ -36,7 +38,7 @@ class Chef begin if user - logon_session = Chef::Util::Windows::LogonSession.new(user, password, domain, logon_type) + logon_session = Chef::Util::Windows::LogonSession.new(user, password, domain, authentication) logon_session.open logon_session.set_user_context end diff --git a/lib/chef/provider/remote_file/network_file.rb b/lib/chef/provider/remote_file/network_file.rb index a7ba0207bd..f9dc7b0e7b 100644 --- a/lib/chef/provider/remote_file/network_file.rb +++ b/lib/chef/provider/remote_file/network_file.rb @@ -43,7 +43,7 @@ class Chef tempfile = Chef::FileContentManagement::Tempfile.new(new_resource).tempfile Chef::Log.debug("#{new_resource} staging #{@source} to #{tempfile.path}") - with_user_context(new_resource.remote_user, new_resource.remote_password, new_resource.remote_domain, :remote) do + with_user_context(new_resource.remote_user, new_resource.remote_password, new_resource.remote_domain, new_resource.authentication) do ::File.open(@source, "rb") do |remote_file| while data = remote_file.read(TRANSFER_CHUNK_SIZE) tempfile.write(data) diff --git a/lib/chef/resource/remote_file.rb b/lib/chef/resource/remote_file.rb index 4db055a20d..d2c2622524 100644 --- a/lib/chef/resource/remote_file.rb +++ b/lib/chef/resource/remote_file.rb @@ -139,6 +139,8 @@ class Chef property :remote_password, String, sensitive: true + property :authentication, equal_to: [:remote, :local], default: :remote + def after_created validate_identity_platform(remote_user, remote_password, remote_domain) identity = qualify_user(remote_user, remote_password, remote_domain) diff --git a/lib/chef/util/windows/logon_session.rb b/lib/chef/util/windows/logon_session.rb index 20c49cfd27..912a603865 100644 --- a/lib/chef/util/windows/logon_session.rb +++ b/lib/chef/util/windows/logon_session.rb @@ -25,7 +25,7 @@ class Chef class LogonSession include Chef::Mixin::WideString - def initialize(username, password, domain = nil, logon_type = :remote) + def initialize(username, password, domain = nil, authentication = :remote) if username.nil? || password.nil? raise ArgumentError, "The logon session must be initialize with non-nil user name and password parameters" end @@ -33,7 +33,7 @@ class Chef @original_username = username @original_password = password @original_domain = domain - @logon_type = logon_type + @authentication = authentication @token = FFI::Buffer.new(:pointer) @session_opened = false @impersonating = false @@ -48,9 +48,9 @@ class Chef password = wstring(original_password) domain = wstring(original_domain) - if logon_type == :remote + if authentication == :remote status = Chef::ReservedNames::Win32::API::Security.LogonUserW(username, domain, password, Chef::ReservedNames::Win32::API::Security::LOGON32_LOGON_NEW_CREDENTIALS, Chef::ReservedNames::Win32::API::Security::LOGON32_PROVIDER_DEFAULT, token) - elsif logon_type == :local + elsif authentication == :local status = Chef::ReservedNames::Win32::API::Security.LogonUserW(username, domain, password, Chef::ReservedNames::Win32::API::Security::LOGON32_LOGON_NETWORK, Chef::ReservedNames::Win32::API::Security::LOGON32_PROVIDER_DEFAULT, token) end @@ -115,7 +115,7 @@ class Chef attr_reader :original_username attr_reader :original_password attr_reader :original_domain - attr_reader :logon_type + attr_reader :authentication attr_reader :token attr_reader :session_opened diff --git a/spec/functional/win32/security_spec.rb b/spec/functional/win32/security_spec.rb index d35f6dea0b..6c24cbec08 100644 --- a/spec/functional/win32/security_spec.rb +++ b/spec/functional/win32/security_spec.rb @@ -39,6 +39,7 @@ describe "Chef::Win32::Security", :windows_only do whoami.error! whoami.stdout.split("\\")[0] end + before do allow_any_instance_of(Chef::Mixin::UserContext).to receive(:node).and_return({ "platform_family" => "windows" }) allow(Chef::Platform).to receive(:windows_server_2003?).and_return(false) diff --git a/spec/unit/util/windows/logon_session_spec.rb b/spec/unit/util/windows/logon_session_spec.rb index 77915c2ae1..8a94802bf6 100644 --- a/spec/unit/util/windows/logon_session_spec.rb +++ b/spec/unit/util/windows/logon_session_spec.rb @@ -27,8 +27,8 @@ describe ::Chef::Util::Windows::LogonSession do stub_const("Chef::ReservedNames::Win32::API::System", Class.new ) end - let(:session) { ::Chef::Util::Windows::LogonSession.new(session_user, password, session_domain, logon_type) } - let(:logon_type) { :remote } + let(:session) { ::Chef::Util::Windows::LogonSession.new(session_user, password, session_domain, authentication) } + let(:authentication) { :remote } shared_examples_for "it received syntactically invalid credentials" do it "does not raisees an exception when it is initialized" do diff --git a/spec/unit/win32/security_spec.rb b/spec/unit/win32/security_spec.rb index 4e22668a93..6e4441a482 100644 --- a/spec/unit/win32/security_spec.rb +++ b/spec/unit/win32/security_spec.rb @@ -64,6 +64,42 @@ describe "Chef::Win32::Security", :windows_only do end end + describe "self.has_admin_privileges?" do + it "returns true for windows server 2003" do + allow(Chef::Platform).to receive(:windows_server_2003?).and_return(true) + expect(Chef::ReservedNames::Win32::Security.has_admin_privileges?).to be true + end + + context "when the user doesn't have admin privileges" do + it "returns false" do + allow(Chef::Platform).to receive(:windows_server_2003?).and_return(false) + allow(Chef::ReservedNames::Win32::Security).to receive(:open_current_process_token).and_raise("Access is denied.") + expect(Chef::ReservedNames::Win32::Security.has_admin_privileges?).to be false + end + end + + context "when open_current_process_token fails with some other error than `Access is Denied`" do + it "raises error" do + allow(Chef::Platform).to receive(:windows_server_2003?).and_return(false) + allow(Chef::ReservedNames::Win32::Security).to receive(:open_current_process_token).and_raise("boom") + expect { Chef::ReservedNames::Win32::Security.has_admin_privileges? }.to raise_error(Chef::Exceptions::Win32APIError) + end + end + + context "when the user has admin privileges" do + it "returns true" do + allow(Chef::Platform).to receive(:windows_server_2003?).and_return(false) + allow(Chef::ReservedNames::Win32::Security).to receive(:open_current_process_token) + token = Chef::ReservedNames::Win32::Security.open_current_process_token + allow(token).to receive_message_chain(:handle, :handle) + allow(Chef::ReservedNames::Win32::Security).to receive(:get_token_information_elevation_type) + allow(Chef::ReservedNames::Win32::Security).to receive(:GetTokenInformation).and_return(true) + allow_any_instance_of(FFI::Buffer).to receive(:read_ulong).and_return(1) + expect(Chef::ReservedNames::Win32::Security.has_admin_privileges?).to be true + end + end + end + describe "self.get_token_information_elevation_type" do let(:token_rights) { Chef::ReservedNames::Win32::Security::TOKEN_READ } |