Skip to content

Commit f6adbd5

Browse files
authored
Merge pull request #8612 from mihaibuzgau/main
(maint) Merge up 6.x to main
2 parents 3aecb85 + 1d25599 commit f6adbd5

File tree

10 files changed

+256
-101
lines changed

10 files changed

+256
-101
lines changed

acceptance/tests/resource/user/osx_10.4_should_fail_when_modify_home.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
test_name "should not modify the home directory of an user on OS X >= 10.14" do
2-
confine :to, :platform => /osx-10.1[4-9]/
2+
confine :to, :platform => /osx/
33

44
tag 'audit:high',
55
'audit:acceptance' # Could be done as integration tests, but would
@@ -23,7 +23,7 @@
2323
end
2424

2525
step "verify the error message is correct" do
26-
expected_error = /OS X version 10\.1[4-9] does not allow changing home using puppet/
26+
expected_error = /OS X version [0-9\.]+ does not allow changing home using puppet/
2727
user_manifest = resource_manifest('user', user, ensure: 'present', home: "/opt/#{user}")
2828

2929
apply_manifest_on(agent, user_manifest) do |result|

acceptance/tests/resource/user/osx_10.4_should_fail_when_modify_uid.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
test_name "should not modify the uid of an user on OS X >= 10.14" do
2-
confine :to, :platform => /osx-10.1[4-9]/
2+
confine :to, :platform => /osx/
33

44
tag 'audit:high',
55
'audit:acceptance' # Could be done as integration tests, but would
@@ -23,7 +23,7 @@
2323
end
2424

2525
step "verify the error message is correct" do
26-
expected_error = /OS X version 10\.1[4-9] does not allow changing uid using puppet/
26+
expected_error = /OS X version [0-9\.]+ does not allow changing uid using puppet/
2727
user_manifest = resource_manifest('user', user, ensure: 'present', uid: rand(999999))
2828

2929
apply_manifest_on(agent, user_manifest) do |result|
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
test_name "should allow managed macOS users to login" do
2+
3+
confine :to, :platform => /osx/
4+
5+
tag 'audit:high',
6+
'audit:acceptance' # Could be done as integration tests, but would
7+
# require changing the system running the test
8+
# in ways that might require special permissions
9+
# or be harmful to the system running the test
10+
11+
12+
# Two different test cases, with additional environment setup inbetween,
13+
# were added in the same file to save on test run time (managing macOS users
14+
# takes around a minute or so because when retrieving plist data from all users with
15+
# `dscl readall` we also receive thousands of bytes of user avatar image)
16+
agents.each do |agent|
17+
teardown do
18+
on(agent, puppet("resource", "user", 'testuser', "ensure=absent"))
19+
end
20+
21+
# Checking if we can create a user with password, salt and iterations
22+
step "create the test user with password and salt" do
23+
# The password is 'helloworld'
24+
apply_manifest_on(agent, <<-MANIFEST, :catch_failures => true)
25+
user { 'testuser':
26+
ensure => present,
27+
password => '6ce97688468f231845d9d982f1f10832ca0c6c728a77bac51c548af99ebd9b9c62bcba15112a0c7a7e34effbb2e92635650c79c51517d72b083a4eb2a513f51ad1f8ea9556cef22456159c341d8bcd382a91708afaf253c2b727d4c6cd3d29cc26011d5d511154037330ecea0263b1be8c1c13086d029c57344291bd37952b56',
28+
salt => '377e8b60e5fdfe509cad188d5b1b9e40e78b418f8c3f0127620ea69d4c32789c',
29+
iterations => 40000,
30+
}
31+
MANIFEST
32+
end
33+
34+
step "verify the password was set correctly and is able to log in" do
35+
on(agent, "dscl /Local/Default -authonly testuser helloworld", :acceptable_exit_codes => 0)
36+
end
37+
38+
unless agent['platform'] =~ /osx-11/
39+
skip_test "AuthenticationAuthority field fix test is not valid for macOS older than Big Sur (11.0)"
40+
end
41+
42+
# Setting up environment to mimic situation on macOS 11 BigSur
43+
# Prior to macOS BigSur, `dscl . -create` was populating more fields with
44+
# default values, including AuthenticationAuthority which contains the
45+
# ShadowHash type
46+
# Withouth this field, login is not allowed
47+
step "remove AuthenticationAuthority field from user" do
48+
on(agent, "dscl /Local/Default -delete Users/testuser AuthenticationAuthority", :acceptable_exit_codes => 0)
49+
end
50+
51+
step "expect user without AuthenticationAuthority to not be able to log in" do
52+
on(agent, "dscl /Local/Default -authonly testuser helloworld", :acceptable_exit_codes => (1..255))
53+
end
54+
55+
# Expecting Puppet to pick up the missing field and add it to
56+
# make the user usable again
57+
step "change password with different salt and expect AuthenticationAuthority field to be readded" do
58+
# The password is still 'helloworld' but with different salt
59+
apply_manifest_on(agent, <<-MANIFEST, { :catch_failures => true, :debug => true }) do |result|
60+
user { 'testuser':
61+
ensure => present,
62+
password => '7e8e82542a0c06595e99bfe10c6bd219d19dede137c5c2f84bf10d98d83b77302d3c9c7f7e3652d420f562613f582ab62b26a52b9b26d0d032efbd486fd865b3ba4fd8a3512137681ce87d190f8fa7848d941c6080c588528dcb682c763c040ff54992dce204c3e5dda973e7b36f7f50a774e55e99fe4c8ed6b6464614838c13',
63+
salt => '8005b8855a187086a3b59eff925a611ec61d2d66d2e786b7598fe0a0b4b8ffba',
64+
iterations => 40000
65+
}
66+
MANIFEST
67+
68+
assert_match(/User 'testuser' is missing the 'SALTED-SHA512-PBKDF2' AuthenticationAuthority key for ShadowHash/, result.stdout)
69+
assert_match(/Adding 'SALTED-SHA512-PBKDF2' AuthenticationAuthority key for ShadowHash to user 'testuser'/, result.stdout)
70+
end
71+
end
72+
73+
step "verify the password was set correctly and is able to log in" do
74+
on(agent, "dscl /Local/Default -authonly testuser helloworld", :acceptable_exit_codes => 0)
75+
end
76+
end
77+
end

acceptance/tests/resource/user/should_allow_password_salt_iterations_osx.rb

Lines changed: 0 additions & 35 deletions
This file was deleted.

lib/puppet/pops/types/p_sensitive_type.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,16 @@ def to_s
2424
def inspect
2525
"#<#{self}>"
2626
end
27+
28+
def hash
29+
@value.hash
30+
end
31+
32+
def ==(other)
33+
other.is_a?(Sensitive) &&
34+
other.hash == hash
35+
end
36+
alias eql? ==
2737
end
2838

2939
def self.register_ptype(loader, ir)

lib/puppet/provider/user/directoryservice.rb

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,7 @@ def salt=(value)
435435
['home', 'uid', 'gid', 'comment', 'shell'].each do |setter_method|
436436
define_method("#{setter_method}=") do |value|
437437
if @property_hash[setter_method.intern]
438-
if self.class.get_os_version.split('.').last.to_i >= 14 && %w(home uid).include?(setter_method)
438+
if %w(home uid).include?(setter_method)
439439
raise Puppet::Error, "OS X version #{self.class.get_os_version} does not allow changing #{setter_method} using puppet"
440440
end
441441
begin
@@ -536,6 +536,14 @@ def write_password_to_users_plist(value)
536536
if (shadow_hash_data.class == Hash) && (shadow_hash_data.has_key?('SALTED-SHA512'))
537537
shadow_hash_data.delete('SALTED-SHA512')
538538
end
539+
540+
# Starting with macOS 11 Big Sur, the AuthenticationAuthority field
541+
# could be missing entirely and without it the managed user cannot log in
542+
if needs_sha512_pbkdf2_authentication_authority_to_be_added?(users_plist)
543+
Puppet.debug("Adding 'SALTED-SHA512-PBKDF2' AuthenticationAuthority key for ShadowHash to user '#{@resource.name}'")
544+
merge_attribute_with_dscl('Users', @resource.name, 'AuthenticationAuthority', ERB::Util.html_escape(SHA512_PBKDF2_AUTHENTICATION_AUTHORITY))
545+
end
546+
539547
set_salted_pbkdf2(users_plist, shadow_hash_data, 'entropy', value)
540548
end
541549
end
@@ -562,6 +570,17 @@ def get_shadow_hash_data(users_plist)
562570
end
563571
end
564572

573+
# This method will check if authentication_authority key of a user's plist
574+
# needs SALTED_SHA512_PBKDF2 to be added. This is a valid case for macOS 11 (Big Sur)
575+
# where users created with `dscl` started to have this field missing
576+
def needs_sha512_pbkdf2_authentication_authority_to_be_added?(users_plist)
577+
authority = users_plist['authentication_authority']
578+
return false if Puppet::Util::Package.versioncmp(self.class.get_os_version, '11.0.0') < 0 && authority && authority.include?(SHA512_PBKDF2_AUTHENTICATION_AUTHORITY)
579+
580+
Puppet.debug("User '#{@resource.name}' is missing the 'SALTED-SHA512-PBKDF2' AuthenticationAuthority key for ShadowHash")
581+
true
582+
end
583+
565584
# This method will embed the binary plist data comprising the user's
566585
# password hash (and Salt/Iterations value if the OS is 10.8 or greater)
567586
# into the ShadowHashData key of the user's plist.
@@ -657,4 +676,8 @@ def set_salted_pbkdf2(users_plist, shadow_hash_data, field, value)
657676
def write_users_plist_to_disk(users_plist)
658677
Puppet::Util::Plist.write_plist_file(users_plist, "#{users_plist_dir}/#{@resource.name}.plist", :binary)
659678
end
679+
680+
private
681+
682+
SHA512_PBKDF2_AUTHENTICATION_AUTHORITY = ';ShadowHash;HASHLIST:<SALTED-SHA512-PBKDF2,SRP-RFC5054-4096-SHA512-PBKDF2>'
660683
end

lib/puppet/type/service.rb

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,12 @@ module Puppet
3838
feature :enableable, "The provider can enable and disable the service.",
3939
:methods => [:disable, :enable, :enabled?]
4040

41+
feature :delayed_startable, "The provider can set service to delayed start",
42+
:methods => [:delayed_start]
43+
44+
feature :manual_startable, "The provider can set service to manual start",
45+
:methods => [:manual_start]
46+
4147
feature :controllable, "The provider uses a control variable."
4248

4349
feature :flaggable, "The provider can pass flags to the service."
@@ -67,7 +73,7 @@ module Puppet
6773
provider.disable
6874
end
6975

70-
newvalue(:manual, :event => :service_manual_start) do
76+
newvalue(:manual, :event => :service_manual_start, :required_features => :manual_startable) do
7177
provider.manual_start
7278
end
7379

@@ -81,21 +87,14 @@ def retrieve
8187
provider.enabled?
8288
end
8389

84-
# This only works on Windows systems.
85-
newvalue(:delayed, :event => :service_delayed_start) do
90+
newvalue(:delayed, :event => :service_delayed_start, :required_features => :delayed_startable) do
8691
provider.delayed_start
8792
end
8893

8994
def insync?(current)
9095
return provider.enabled_insync?(current) if provider.respond_to?(:enabled_insync?)
9196
super(current)
9297
end
93-
94-
validate do |value|
95-
if (value == :manual || value == :delayed) && !Puppet::Util::Platform.windows?
96-
raise Puppet::Error.new(_("Setting enable to %{value} is only supported on Microsoft Windows.") % { value: value.to_s} )
97-
end
98-
end
9998
end
10099

101100
# Handle whether the service should actually be running right now.

spec/unit/pops/types/p_sensitive_type_spec.rb

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,24 @@ module Types
113113
expect(eval_and_collect_notices(code)).to eq(['Sensitive[Integer] != Sensitive[String]'])
114114
end
115115

116+
it 'equals another instance with the same value' do
117+
code =<<-CODE
118+
$i = Sensitive('secret')
119+
$o = Sensitive('secret')
120+
notice($i == $o)
121+
CODE
122+
expect(eval_and_collect_notices(code)).to eq(['true'])
123+
end
124+
125+
it 'has equal hash keys for same values' do
126+
code =<<-CODE
127+
$i = Sensitive('secret')
128+
$o = Sensitive('secret')
129+
notice({$i => 1} == {$o => 1})
130+
CODE
131+
expect(eval_and_collect_notices(code)).to eq(['true'])
132+
end
133+
116134
it 'can be created from another sensitive instance ' do
117135
code =<<-CODE
118136
$o = Sensitive("hunter2")

spec/unit/provider/user/directoryservice_spec.rb

Lines changed: 66 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -925,28 +925,75 @@ module Puppet::Util::Plist
925925
}
926926
end
927927

928-
it 'should call set_salted_sha512 on 10.7 when given a salted-SHA512 password hash' do
929-
expect(provider).to receive(:get_users_plist).and_return(sample_users_plist)
930-
expect(provider).to receive(:get_shadow_hash_data).with(sample_users_plist).and_return(sha512_shadowhashdata)
931-
expect(provider.class).to receive(:get_os_version).and_return('10.7')
932-
expect(provider).to receive(:set_salted_sha512).with(sample_users_plist, sha512_shadowhashdata, sha512_password_hash)
933-
provider.write_password_to_users_plist(sha512_password_hash)
928+
before do
929+
allow(provider).to receive(:merge_attribute_with_dscl).with('Users', username, 'AuthenticationAuthority', any_args)
934930
end
935931

936-
it 'should call set_salted_pbkdf2 on 10.8 when given a PBKDF2 password hash' do
937-
expect(provider).to receive(:get_users_plist).and_return(sample_users_plist)
938-
expect(provider).to receive(:get_shadow_hash_data).with(sample_users_plist).and_return(pbkdf2_shadowhashdata)
939-
expect(provider.class).to receive(:get_os_version).and_return('10.8')
940-
expect(provider).to receive(:set_salted_pbkdf2).with(sample_users_plist, pbkdf2_shadowhashdata, 'entropy', pbkdf2_password_hash)
941-
provider.write_password_to_users_plist(pbkdf2_password_hash)
932+
describe 'when on macOS 11 (Big Sur) or greater' do
933+
before do
934+
allow(provider.class).to receive(:get_os_version).and_return('11.0.0')
935+
end
936+
937+
it 'should add salted_sha512_pbkdf2 AuthenticationAuthority key if missing' do
938+
expect(provider).to receive(:get_users_plist).and_return(sample_users_plist)
939+
expect(provider).to receive(:get_shadow_hash_data).with(sample_users_plist).and_return(pbkdf2_shadowhashdata)
940+
expect(provider).to receive(:set_salted_pbkdf2).with(sample_users_plist, pbkdf2_shadowhashdata, 'entropy', pbkdf2_password_hash)
941+
expect(provider).to receive(:needs_sha512_pbkdf2_authentication_authority_to_be_added?).and_return(true)
942+
943+
expect(Puppet).to receive(:debug).with("Adding 'SALTED-SHA512-PBKDF2' AuthenticationAuthority key for ShadowHash to user 'nonexistent_user'")
944+
provider.write_password_to_users_plist(pbkdf2_password_hash)
945+
end
946+
947+
it 'should not add salted_sha512_pbkdf2 AuthenticationAuthority key if not missing' do
948+
expect(provider).to receive(:get_users_plist).and_return(sample_users_plist)
949+
expect(provider).to receive(:get_shadow_hash_data).with(sample_users_plist).and_return(pbkdf2_shadowhashdata)
950+
expect(provider).to receive(:set_salted_pbkdf2).with(sample_users_plist, pbkdf2_shadowhashdata, 'entropy', pbkdf2_password_hash)
951+
expect(provider).to receive(:needs_sha512_pbkdf2_authentication_authority_to_be_added?).and_return(false)
952+
953+
expect(Puppet).not_to receive(:debug).with("Adding 'SALTED-SHA512-PBKDF2' AuthenticationAuthority key for ShadowHash to user 'nonexistent_user'")
954+
provider.write_password_to_users_plist(pbkdf2_password_hash)
955+
end
942956
end
943957

944-
it "should delete the SALTED-SHA512 key in the shadow_hash_data hash if it exists on a 10.8 system and write_password_to_users_plist has been called to set the user's password" do
945-
expect(provider).to receive(:get_users_plist).and_return('users_plist')
946-
expect(provider).to receive(:get_shadow_hash_data).with('users_plist').and_return(sha512_shadowhashdata)
947-
expect(provider.class).to receive(:get_os_version).and_return('10.8')
948-
expect(provider).to receive(:set_salted_pbkdf2).with('users_plist', {}, 'entropy', pbkdf2_password_hash)
949-
provider.write_password_to_users_plist(pbkdf2_password_hash)
958+
describe 'when on macOS version lower than 11' do
959+
before do
960+
allow(provider.class).to receive(:get_os_version)
961+
allow(provider).to receive(:needs_sha512_pbkdf2_authentication_authority_to_be_added?).and_return(false)
962+
end
963+
964+
it 'should not add salted_sha512_pbkdf2 AuthenticationAuthority' do
965+
expect(provider).to receive(:get_users_plist).and_return(sample_users_plist)
966+
expect(provider).to receive(:get_shadow_hash_data).with(sample_users_plist).and_return(pbkdf2_shadowhashdata)
967+
expect(provider).to receive(:set_salted_pbkdf2).with(sample_users_plist, pbkdf2_shadowhashdata, 'entropy', pbkdf2_password_hash)
968+
expect(provider).to receive(:needs_sha512_pbkdf2_authentication_authority_to_be_added?).and_return(false)
969+
970+
expect(Puppet).not_to receive(:debug).with("Adding 'SALTED-SHA512-PBKDF2' AuthenticationAuthority key for ShadowHash to user 'nonexistent_user'")
971+
provider.write_password_to_users_plist(pbkdf2_password_hash)
972+
end
973+
974+
it 'should call set_salted_sha512 on 10.7 when given a salted-SHA512 password hash' do
975+
expect(provider).to receive(:get_users_plist).and_return(sample_users_plist)
976+
expect(provider).to receive(:get_shadow_hash_data).with(sample_users_plist).and_return(sha512_shadowhashdata)
977+
expect(provider.class).to receive(:get_os_version).and_return('10.7')
978+
expect(provider).to receive(:set_salted_sha512).with(sample_users_plist, sha512_shadowhashdata, sha512_password_hash)
979+
provider.write_password_to_users_plist(sha512_password_hash)
980+
end
981+
982+
it 'should call set_salted_pbkdf2 on 10.8 when given a PBKDF2 password hash' do
983+
expect(provider).to receive(:get_users_plist).and_return(sample_users_plist)
984+
expect(provider).to receive(:get_shadow_hash_data).with(sample_users_plist).and_return(pbkdf2_shadowhashdata)
985+
expect(provider.class).to receive(:get_os_version).and_return('10.8')
986+
expect(provider).to receive(:set_salted_pbkdf2).with(sample_users_plist, pbkdf2_shadowhashdata, 'entropy', pbkdf2_password_hash)
987+
provider.write_password_to_users_plist(pbkdf2_password_hash)
988+
end
989+
990+
it "should delete the SALTED-SHA512 key in the shadow_hash_data hash if it exists on a 10.8 system and write_password_to_users_plist has been called to set the user's password" do
991+
expect(provider).to receive(:get_users_plist).and_return('users_plist')
992+
expect(provider).to receive(:get_shadow_hash_data).with('users_plist').and_return(sha512_shadowhashdata)
993+
expect(provider.class).to receive(:get_os_version).and_return('10.8')
994+
expect(provider).to receive(:set_salted_pbkdf2).with('users_plist', {}, 'entropy', pbkdf2_password_hash)
995+
provider.write_password_to_users_plist(pbkdf2_password_hash)
996+
end
950997
end
951998
end
952999

@@ -1203,6 +1250,7 @@ module Puppet::Util::Plist
12031250
before :each do
12041251
allow(provider.class).to receive(:get_all_users).and_return(all_users_hash)
12051252
allow(provider.class).to receive(:get_list_of_groups).and_return(group_plist_hash_guid)
1253+
allow(provider).to receive(:merge_attribute_with_dscl).with('Users', username, 'AuthenticationAuthority', any_args)
12061254
provider.class.prefetch({})
12071255
end
12081256

0 commit comments

Comments
 (0)