1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
|
#
# Copyright:: Copyright (c) 2015 Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
require "spec_helper"
require "chef/win32/api" if ChefUtils.windows?
require "chef/win32/api/error" if ChefUtils.windows?
require "chef/mixin/user_context"
describe Chef::Mixin::UserContext, windows_only: true do
include Chef::Mixin::UserContext
let(:get_user_name_a) do
FFI.ffi_lib "advapi32.dll"
FFI.attach_function :GetUserNameA, %i{pointer pointer}, :bool
end
let(:process_username) do
name_size = FFI::Buffer.new(:long).write_long(0)
succeeded = get_user_name_a.call(nil, name_size)
last_error = FFI::LastError.error
if succeeded || last_error != Chef::ReservedNames::Win32::API::Error::ERROR_INSUFFICIENT_BUFFER
raise Chef::Exceptions::Win32APIError, "Expected ERROR_INSUFFICIENT_BUFFER from GetUserNameA but it returned the following error: #{last_error}"
end
user_name = FFI::MemoryPointer.new :char, (name_size.read_long)
succeeded = get_user_name_a.call(user_name, name_size)
last_error = FFI::LastError.error
if succeeded == 0 || last_error != 0
raise Chef::Exceptions::Win32APIError, "GetUserNameA failed with #{lasterror}"
end
user_name.read_string
end
let(:test_user) { "chefuserctx3" }
let(:test_domain) { windows_nonadmin_user_domain }
let(:test_password) { "j823jfxK3;2Xe1" }
let(:username_domain_qualification) { nil }
let(:username_with_conditional_domain) { username_domain_qualification.nil? ? username_to_impersonate : "#{username_domain_qualification}\\#{username_to_impersonate}" }
let(:windows_nonadmin_user) { test_user }
let(:windows_nonadmin_user_password) { test_password }
let(:username_while_impersonating) do
username = nil
with_user_context(username_with_conditional_domain, username_to_impersonate_password, domain_to_impersonate) do
username = process_username
end
username
end
before do
allow_any_instance_of(described_class).to receive(:node).and_return({ "platform_family" => "windows" })
end
shared_examples_for "method that executes the block while impersonating the alternate user" do
it "uses different credentials for other network connections" do
allow_any_instance_of(Chef::Util::Windows::LogonSession).to receive(:validate_session_open!).and_return(true)
expect(username_while_impersonating.downcase).not_to eq(username_to_impersonate.downcase)
end
end
describe "#with_user_context" do
context "when the user and domain are both nil" do
let(:username_to_impersonate) { nil }
let(:domain_to_impersonate) { nil }
let(:username_to_impersonate_password) { nil }
it "has the same token and username as the process" do
expect(username_while_impersonating.downcase).to eq(ENV["username"].downcase)
end
end
context "when a non-nil user is specified" do
include_context "a non-admin Windows user"
context "when a username different than the process user is specified" do
let(:username_to_impersonate) { test_user }
let(:username_to_impersonate_password) { test_password }
context "when an explicit domain is given with a valid password" do
let(:domain_to_impersonate) { test_domain }
it "uses different credentials for other network connections" do
expect(username_while_impersonating.downcase).not_to eq(username_to_impersonate.downcase)
end
end
context "when a valid password and a non-qualified user is given and no domain is specified" do
let(:domain_to_impersonate) { "." }
it_behaves_like "method that executes the block while impersonating the alternate user"
end
it "raises an error user if specified with the wrong password" do
expect { with_user_context(username_to_impersonate, username_to_impersonate_password + "1", nil) }.to raise_error(ArgumentError)
end
end
end
context "when invalid arguments are passed" do
it "raises an ArgumentError exception if the password is not specified but the user is specified" do
expect { with_user_context(test_user, nil, nil) }.to raise_error(ArgumentError)
end
end
end
end
|