puppet 6.21.0-x64-mingw32 → 6.24.0-x64-mingw32

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of puppet might be problematic. Click here for more details.

Files changed (217) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTING.md +5 -5
  3. data/Gemfile +1 -1
  4. data/Gemfile.lock +29 -23
  5. data/README.md +4 -4
  6. data/ext/osx/puppet.plist +2 -0
  7. data/ext/project_data.yaml +3 -2
  8. data/lib/puppet.rb +3 -3
  9. data/lib/puppet/application/agent.rb +12 -5
  10. data/lib/puppet/application/apply.rb +2 -1
  11. data/lib/puppet/application/device.rb +2 -1
  12. data/lib/puppet/application/filebucket.rb +1 -0
  13. data/lib/puppet/application/resource.rb +17 -3
  14. data/lib/puppet/application/script.rb +2 -1
  15. data/lib/puppet/application/ssl.rb +12 -0
  16. data/lib/puppet/configurer/downloader.rb +2 -1
  17. data/lib/puppet/defaults.rb +27 -5
  18. data/lib/puppet/environments.rb +26 -1
  19. data/lib/puppet/face/facts.rb +128 -30
  20. data/lib/puppet/face/help/action.erb +1 -0
  21. data/lib/puppet/face/help/face.erb +1 -0
  22. data/lib/puppet/face/node/clean.rb +11 -0
  23. data/lib/puppet/file_serving/fileset.rb +14 -2
  24. data/lib/puppet/file_system/file_impl.rb +1 -1
  25. data/lib/puppet/file_system/memory_file.rb +8 -1
  26. data/lib/puppet/file_system/windows.rb +4 -2
  27. data/lib/puppet/forge.rb +3 -3
  28. data/lib/puppet/functions/all.rb +1 -1
  29. data/lib/puppet/functions/camelcase.rb +1 -1
  30. data/lib/puppet/functions/capitalize.rb +2 -2
  31. data/lib/puppet/functions/downcase.rb +2 -2
  32. data/lib/puppet/functions/empty.rb +8 -0
  33. data/lib/puppet/functions/get.rb +5 -5
  34. data/lib/puppet/functions/group_by.rb +13 -5
  35. data/lib/puppet/functions/lest.rb +1 -1
  36. data/lib/puppet/functions/new.rb +100 -100
  37. data/lib/puppet/functions/partition.rb +12 -4
  38. data/lib/puppet/functions/require.rb +5 -5
  39. data/lib/puppet/functions/sort.rb +3 -3
  40. data/lib/puppet/functions/strftime.rb +1 -0
  41. data/lib/puppet/functions/tree_each.rb +7 -9
  42. data/lib/puppet/functions/type.rb +4 -4
  43. data/lib/puppet/functions/unwrap.rb +17 -2
  44. data/lib/puppet/functions/upcase.rb +2 -2
  45. data/lib/puppet/http/resolver/server_list.rb +15 -4
  46. data/lib/puppet/http/service/compiler.rb +69 -0
  47. data/lib/puppet/http/service/file_server.rb +2 -1
  48. data/lib/puppet/indirector/catalog/compiler.rb +1 -0
  49. data/lib/puppet/indirector/facts/facter.rb +24 -3
  50. data/lib/puppet/indirector/file_metadata/rest.rb +1 -0
  51. data/lib/puppet/indirector/resource/ral.rb +6 -1
  52. data/lib/puppet/interface/documentation.rb +1 -0
  53. data/lib/puppet/module_tool/applications/installer.rb +4 -0
  54. data/lib/puppet/module_tool/errors/shared.rb +17 -0
  55. data/lib/puppet/network/formats.rb +67 -0
  56. data/lib/puppet/network/http/factory.rb +4 -0
  57. data/lib/puppet/parser/functions/fqdn_rand.rb +14 -6
  58. data/lib/puppet/pops/types/p_sem_ver_type.rb +8 -2
  59. data/lib/puppet/pops/types/p_sensitive_type.rb +10 -0
  60. data/lib/puppet/pops/types/type_mismatch_describer.rb +1 -1
  61. data/lib/puppet/provider/exec/posix.rb +16 -4
  62. data/lib/puppet/provider/package/dnfmodule.rb +1 -1
  63. data/lib/puppet/provider/package/nim.rb +11 -6
  64. data/lib/puppet/provider/package/pip.rb +15 -3
  65. data/lib/puppet/provider/parsedfile.rb +3 -0
  66. data/lib/puppet/provider/service/systemd.rb +14 -4
  67. data/lib/puppet/provider/service/windows.rb +38 -0
  68. data/lib/puppet/provider/user/directoryservice.rb +25 -12
  69. data/lib/puppet/provider/user/useradd.rb +9 -2
  70. data/lib/puppet/reference/configuration.rb +1 -1
  71. data/lib/puppet/settings.rb +30 -7
  72. data/lib/puppet/settings/environment_conf.rb +1 -0
  73. data/lib/puppet/transaction/additional_resource_generator.rb +1 -1
  74. data/lib/puppet/type/exec.rb +16 -3
  75. data/lib/puppet/type/file.rb +19 -1
  76. data/lib/puppet/type/file/mode.rb +6 -0
  77. data/lib/puppet/type/file/selcontext.rb +1 -1
  78. data/lib/puppet/type/service.rb +18 -38
  79. data/lib/puppet/type/tidy.rb +22 -3
  80. data/lib/puppet/type/user.rb +38 -20
  81. data/lib/puppet/util/fact_dif.rb +36 -17
  82. data/lib/puppet/util/monkey_patches.rb +7 -0
  83. data/lib/puppet/util/selinux.rb +30 -4
  84. data/lib/puppet/util/symbolic_file_mode.rb +29 -17
  85. data/lib/puppet/util/windows/adsi.rb +46 -0
  86. data/lib/puppet/util/windows/api_types.rb +1 -1
  87. data/lib/puppet/util/windows/principal.rb +9 -2
  88. data/lib/puppet/util/windows/sid.rb +6 -2
  89. data/lib/puppet/version.rb +1 -1
  90. data/locales/puppet.pot +360 -280
  91. data/man/man5/puppet.conf.5 +279 -251
  92. data/man/man8/puppet-agent.8 +1 -1
  93. data/man/man8/puppet-apply.8 +1 -1
  94. data/man/man8/puppet-catalog.8 +9 -9
  95. data/man/man8/puppet-config.8 +1 -1
  96. data/man/man8/puppet-describe.8 +1 -1
  97. data/man/man8/puppet-device.8 +1 -1
  98. data/man/man8/puppet-doc.8 +1 -1
  99. data/man/man8/puppet-epp.8 +1 -1
  100. data/man/man8/puppet-facts.8 +65 -7
  101. data/man/man8/puppet-filebucket.8 +1 -1
  102. data/man/man8/puppet-generate.8 +1 -1
  103. data/man/man8/puppet-help.8 +1 -1
  104. data/man/man8/puppet-key.8 +7 -7
  105. data/man/man8/puppet-lookup.8 +1 -1
  106. data/man/man8/puppet-man.8 +1 -1
  107. data/man/man8/puppet-module.8 +1 -1
  108. data/man/man8/puppet-node.8 +5 -5
  109. data/man/man8/puppet-parser.8 +1 -1
  110. data/man/man8/puppet-plugin.8 +1 -1
  111. data/man/man8/puppet-report.8 +5 -5
  112. data/man/man8/puppet-resource.8 +1 -1
  113. data/man/man8/puppet-script.8 +1 -1
  114. data/man/man8/puppet-ssl.8 +5 -1
  115. data/man/man8/puppet-status.8 +4 -4
  116. data/man/man8/puppet.8 +2 -2
  117. data/spec/fixtures/ssl/127.0.0.1-key.pem +107 -57
  118. data/spec/fixtures/ssl/127.0.0.1.pem +52 -31
  119. data/spec/fixtures/ssl/bad-basic-constraints.pem +57 -35
  120. data/spec/fixtures/ssl/bad-int-basic-constraints.pem +57 -35
  121. data/spec/fixtures/ssl/ca.pem +57 -35
  122. data/spec/fixtures/ssl/crl.pem +28 -18
  123. data/spec/fixtures/ssl/ec-key.pem +11 -11
  124. data/spec/fixtures/ssl/ec.pem +33 -24
  125. data/spec/fixtures/ssl/encrypted-ec-key.pem +12 -12
  126. data/spec/fixtures/ssl/encrypted-key.pem +108 -58
  127. data/spec/fixtures/ssl/intermediate-agent-crl.pem +28 -19
  128. data/spec/fixtures/ssl/intermediate-agent.pem +57 -36
  129. data/spec/fixtures/ssl/intermediate-crl.pem +31 -21
  130. data/spec/fixtures/ssl/intermediate.pem +57 -36
  131. data/spec/fixtures/ssl/oid-key.pem +117 -0
  132. data/spec/fixtures/ssl/oid.pem +69 -0
  133. data/spec/fixtures/ssl/pluto-key.pem +107 -57
  134. data/spec/fixtures/ssl/pluto.pem +52 -30
  135. data/spec/fixtures/ssl/request-key.pem +107 -57
  136. data/spec/fixtures/ssl/request.pem +47 -26
  137. data/spec/fixtures/ssl/revoked-key.pem +107 -57
  138. data/spec/fixtures/ssl/revoked.pem +52 -30
  139. data/spec/fixtures/ssl/signed-key.pem +107 -57
  140. data/spec/fixtures/ssl/signed.pem +52 -30
  141. data/spec/fixtures/ssl/tampered-cert.pem +52 -30
  142. data/spec/fixtures/ssl/tampered-csr.pem +47 -26
  143. data/spec/fixtures/ssl/trusted_oid_mapping.yaml +5 -0
  144. data/spec/fixtures/ssl/unknown-127.0.0.1-key.pem +107 -57
  145. data/spec/fixtures/ssl/unknown-127.0.0.1.pem +50 -29
  146. data/spec/fixtures/ssl/unknown-ca-key.pem +107 -57
  147. data/spec/fixtures/ssl/unknown-ca.pem +55 -33
  148. data/spec/fixtures/unit/provider/service/systemd/list_unit_files_services_vendor_preset +9 -0
  149. data/spec/integration/application/filebucket_spec.rb +11 -0
  150. data/spec/integration/application/module_spec.rb +21 -0
  151. data/spec/integration/application/plugin_spec.rb +1 -1
  152. data/spec/integration/application/resource_spec.rb +64 -0
  153. data/spec/integration/application/ssl_spec.rb +20 -0
  154. data/spec/integration/environments/settings_interpolation_spec.rb +0 -4
  155. data/spec/integration/http/client_spec.rb +12 -0
  156. data/spec/integration/indirector/direct_file_server_spec.rb +1 -3
  157. data/spec/integration/indirector/facts/facter_spec.rb +90 -36
  158. data/spec/integration/type/exec_spec.rb +70 -45
  159. data/spec/integration/util/windows/adsi_spec.rb +18 -0
  160. data/spec/integration/util/windows/principal_spec.rb +21 -0
  161. data/spec/integration/util/windows/registry_spec.rb +6 -0
  162. data/spec/lib/puppet/test_ca.rb +7 -2
  163. data/spec/lib/puppet_spec/settings.rb +1 -0
  164. data/spec/spec_helper.rb +11 -1
  165. data/spec/unit/application/agent_spec.rb +7 -2
  166. data/spec/unit/application/facts_spec.rb +482 -3
  167. data/spec/unit/application/ssl_spec.rb +23 -0
  168. data/spec/unit/configurer/downloader_spec.rb +6 -0
  169. data/spec/unit/configurer_spec.rb +23 -0
  170. data/spec/unit/defaults_spec.rb +16 -0
  171. data/spec/unit/environments_spec.rb +199 -88
  172. data/spec/unit/face/facts_spec.rb +4 -0
  173. data/spec/unit/file_serving/fileset_spec.rb +60 -0
  174. data/spec/unit/file_system_spec.rb +15 -0
  175. data/spec/unit/functions/assert_type_spec.rb +1 -1
  176. data/spec/unit/functions/empty_spec.rb +10 -0
  177. data/spec/unit/functions/unwrap_spec.rb +8 -0
  178. data/spec/unit/functions4_spec.rb +2 -2
  179. data/spec/unit/gettext/config_spec.rb +12 -0
  180. data/spec/unit/http/service/compiler_spec.rb +123 -0
  181. data/spec/unit/indirector/catalog/compiler_spec.rb +14 -10
  182. data/spec/unit/indirector/facts/facter_spec.rb +95 -0
  183. data/spec/unit/indirector/resource/ral_spec.rb +40 -75
  184. data/spec/unit/module_tool/applications/installer_spec.rb +12 -0
  185. data/spec/unit/network/formats_spec.rb +41 -0
  186. data/spec/unit/network/http/factory_spec.rb +19 -0
  187. data/spec/unit/parser/functions/fqdn_rand_spec.rb +15 -1
  188. data/spec/unit/parser/templatewrapper_spec.rb +12 -2
  189. data/spec/unit/pops/types/p_sem_ver_type_spec.rb +18 -0
  190. data/spec/unit/pops/types/p_sensitive_type_spec.rb +18 -0
  191. data/spec/unit/provider/package/dnfmodule_spec.rb +10 -1
  192. data/spec/unit/provider/package/nim_spec.rb +42 -0
  193. data/spec/unit/provider/package/pip_spec.rb +37 -0
  194. data/spec/unit/provider/parsedfile_spec.rb +10 -0
  195. data/spec/unit/provider/service/init_spec.rb +1 -0
  196. data/spec/unit/provider/service/openwrt_spec.rb +3 -1
  197. data/spec/unit/provider/service/systemd_spec.rb +53 -8
  198. data/spec/unit/provider/service/windows_spec.rb +202 -0
  199. data/spec/unit/provider/user/directoryservice_spec.rb +67 -35
  200. data/spec/unit/provider/user/useradd_spec.rb +21 -6
  201. data/spec/unit/resource/catalog_spec.rb +1 -1
  202. data/spec/unit/settings_spec.rb +97 -56
  203. data/spec/unit/ssl/state_machine_spec.rb +19 -5
  204. data/spec/unit/transaction/additional_resource_generator_spec.rb +0 -2
  205. data/spec/unit/transaction_spec.rb +18 -20
  206. data/spec/unit/type/exec_spec.rb +76 -29
  207. data/spec/unit/type/file/selinux_spec.rb +3 -3
  208. data/spec/unit/type/file/source_spec.rb +4 -4
  209. data/spec/unit/type/service_spec.rb +59 -188
  210. data/spec/unit/type/tidy_spec.rb +24 -7
  211. data/spec/unit/type/user_spec.rb +45 -0
  212. data/spec/unit/util/selinux_spec.rb +87 -16
  213. data/spec/unit/util/windows/sid_spec.rb +41 -0
  214. data/tasks/generate_cert_fixtures.rake +12 -3
  215. metadata +24 -9
  216. data/spec/lib/matchers/include.rb +0 -27
  217. data/spec/lib/matchers/include_spec.rb +0 -32
@@ -266,6 +266,43 @@ describe Puppet::Type.type(:package).provider(:pip) do
266
266
  let(:pip_version) { '1.5.4' }
267
267
  let(:pip_path) { '/fake/bin/pip' }
268
268
 
269
+ context "with pip version >= 20.3 and < 21.1" do
270
+ let(:pip_version) { '20.3.1' }
271
+ let(:pip_path) { '/fake/bin/pip' }
272
+
273
+ it "should use legacy-resolver argument" do
274
+ p = StringIO.new(
275
+ <<-EOS
276
+ Collecting real-package==versionplease
277
+ Could not find a version that satisfies the requirement real-package==versionplease (from versions: 1.1.3, 1.0, 1.9b1)
278
+ No matching distribution found for real-package==versionplease
279
+ EOS
280
+ )
281
+ expect(Puppet::Util::Execution).to receive(:execpipe).with(["/fake/bin/pip", "install", "real_package==versionplease",
282
+ "--use-deprecated=legacy-resolver"]).and_yield(p).once
283
+ @resource[:name] = "real_package"
284
+ @provider.latest
285
+ end
286
+ end
287
+
288
+ context "with pip version >= 21.1" do
289
+ let(:pip_version) { '21.1' }
290
+ let(:pip_path) { '/fake/bin/pip' }
291
+
292
+ it "should not use legacy-resolver argument" do
293
+ p = StringIO.new(
294
+ <<-EOS
295
+ Collecting real-package==versionplease
296
+ Could not find a version that satisfies the requirement real-package==versionplease (from versions: 1.1.3, 1.0, 1.9b1)
297
+ No matching distribution found for real-package==versionplease
298
+ EOS
299
+ )
300
+ expect(Puppet::Util::Execution).to receive(:execpipe).with(["/fake/bin/pip", "install", "real_package==versionplease"]).and_yield(p).once
301
+ @resource[:name] = "real_package"
302
+ @provider.latest
303
+ end
304
+ end
305
+
269
306
  it "should find a version number for real_package" do
270
307
  p = StringIO.new(
271
308
  <<-EOS
@@ -79,6 +79,16 @@ describe Puppet::Provider::ParsedFile do
79
79
 
80
80
  provider.instances
81
81
  end
82
+
83
+ it "should raise if parsing returns nil" do
84
+ expect(provider).to receive(:targets).and_return(%w{/one})
85
+ expect_any_instance_of(Puppet::Util::FileType::FileTypeFlat).to receive(:read).and_return('a=b')
86
+ expect(provider).to receive(:parse).and_return(nil)
87
+
88
+ expect {
89
+ provider.instances
90
+ }.to raise_error(Puppet::DevError, %r{Prefetching /one for provider parsedfile_provider returned nil})
91
+ end
82
92
  end
83
93
 
84
94
  describe "when matching resources to existing records" do
@@ -83,6 +83,7 @@ describe 'Puppet::Type::Service::Provider::Init',
83
83
  allow(provider_class).to receive(:defpath).and_return('tmp')
84
84
 
85
85
  @services = ['one', 'two', 'three', 'four', 'umountfs']
86
+ allow(Dir).to receive(:entries).and_call_original
86
87
  allow(Dir).to receive(:entries).with('tmp').and_return(@services)
87
88
  expect(FileTest).to receive(:directory?).with('tmp').and_return(true)
88
89
  allow(FileTest).to receive(:executable?).and_return(true)
@@ -32,6 +32,7 @@ describe 'Puppet::Type::Service::Provider::Openwrt',
32
32
  allow(File).to receive(:directory?).with('/etc/init.d').and_return(true)
33
33
 
34
34
  allow(Puppet::FileSystem).to receive(:exist?).with('/etc/init.d/myservice').and_return(true)
35
+ allow(FileTest).to receive(:file?).and_call_original
35
36
  allow(FileTest).to receive(:file?).with('/etc/init.d/myservice').and_return(true)
36
37
  allow(FileTest).to receive(:executable?).with('/etc/init.d/myservice').and_return(true)
37
38
  end
@@ -47,7 +48,8 @@ describe 'Puppet::Type::Service::Provider::Openwrt',
47
48
  let(:services) {['dnsmasq', 'dropbear', 'firewall', 'led', 'puppet', 'uhttpd' ]}
48
49
 
49
50
  before :each do
50
- allow(Dir).to receive(:entries).and_return(services)
51
+ allow(Dir).to receive(:entries).and_call_original
52
+ allow(Dir).to receive(:entries).with('/etc/init.d').and_return(services)
51
53
  allow(FileTest).to receive(:directory?).and_return(true)
52
54
  allow(FileTest).to receive(:executable?).and_return(true)
53
55
  end
@@ -200,6 +200,17 @@ describe 'Puppet::Type::Service::Provider::Systemd',
200
200
  })
201
201
  end
202
202
 
203
+ it "correctly parses services when list-unit-files has an additional column" do
204
+ expect(provider_class).to receive(:systemctl).with('list-unit-files', '--type', 'service', '--full', '--all', '--no-pager').and_return(File.read(my_fixture('list_unit_files_services_vendor_preset')))
205
+ expect(provider_class.instances.map(&:name)).to match_array(%w{
206
+ arp-ethers.service
207
+ auditd.service
208
+ dbus.service
209
+ umountnfs.service
210
+ urandom.service
211
+ })
212
+ end
213
+
203
214
  it "should print a debug message when a service with the state `bad` is found" do
204
215
  expect(provider_class).to receive(:systemctl).with('list-unit-files', '--type', 'service', '--full', '--all', '--no-pager').and_return(File.read(my_fixture('list_unit_files_services')))
205
216
  expect(Puppet).to receive(:debug).with("apparmor.service marked as bad by `systemctl`. It is recommended to be further checked.")
@@ -346,6 +357,9 @@ Jun 14 21:43:23 foo.example.com systemd[1]: sshd.service lacks both ExecStart= a
346
357
  describe "#mask" do
347
358
  it "should run systemctl to disable and mask a service" do
348
359
  provider = provider_class.new(Puppet::Type.type(:service).new(:name => 'sshd.service'))
360
+ expect(provider).to receive(:execute).
361
+ with(['/bin/systemctl','cat', '--', 'sshd.service'], :failonfail => false).
362
+ and_return(Puppet::Util::Execution::ProcessOutput.new("# /lib/systemd/system/sshd.service\n...", 0))
349
363
  # :disable is the only call in the provider that uses a symbol instead of
350
364
  # a string.
351
365
  # This should be made consistent in the future and all tests updated.
@@ -353,6 +367,15 @@ Jun 14 21:43:23 foo.example.com systemd[1]: sshd.service lacks both ExecStart= a
353
367
  expect(provider).to receive(:systemctl).with(:mask, '--', 'sshd.service')
354
368
  provider.mask
355
369
  end
370
+
371
+ it "masks a service that doesn't exist" do
372
+ provider = provider_class.new(Puppet::Type.type(:service).new(:name => 'doesnotexist.service'))
373
+ expect(provider).to receive(:execute).
374
+ with(['/bin/systemctl','cat', '--', 'doesnotexist.service'], :failonfail => false).
375
+ and_return(Puppet::Util::Execution::ProcessOutput.new("No files found for doesnotexist.service.\n", 1))
376
+ expect(provider).to receive(:systemctl).with(:mask, '--', 'doesnotexist.service')
377
+ provider.mask
378
+ end
356
379
  end
357
380
 
358
381
  # Note: systemd provider does not care about hasstatus or a custom status
@@ -456,17 +479,39 @@ Jun 14 21:43:23 foo.example.com systemd[1]: sshd.service lacks both ExecStart= a
456
479
  context 'when service state is static' do
457
480
  let(:service_state) { 'static' }
458
481
 
459
- it 'is always enabled_insync even if current value is the same as expected' do
460
- expect(provider).to be_enabled_insync(:false)
461
- end
482
+ context 'when enable is not mask' do
483
+ it 'is always enabled_insync even if current value is the same as expected' do
484
+ expect(provider).to be_enabled_insync(:false)
485
+ end
462
486
 
463
- it 'is always enabled_insync even if current value is not the same as expected' do
464
- expect(provider).to be_enabled_insync(:true)
487
+ it 'is always enabled_insync even if current value is not the same as expected' do
488
+ expect(provider).to be_enabled_insync(:true)
489
+ end
490
+
491
+ it 'logs a debug messsage' do
492
+ expect(Puppet).to receive(:debug).with("Unable to enable or disable static service sshd.service")
493
+ provider.enabled_insync?(:true)
494
+ end
465
495
  end
466
496
 
467
- it 'logs a debug messsage' do
468
- expect(Puppet).to receive(:debug).with("Unable to enable or disable static service sshd.service")
469
- provider.enabled_insync?(:true)
497
+ context 'when enable is mask' do
498
+ let(:provider) do
499
+ provider_class.new(Puppet::Type.type(:service).new(:name => 'sshd.service',
500
+ :enable => 'mask'))
501
+ end
502
+
503
+ it 'is enabled_insync if current value is the same as expected' do
504
+ expect(provider).to be_enabled_insync(:mask)
505
+ end
506
+
507
+ it 'is not enabled_insync if current value is not the same as expected' do
508
+ expect(provider).not_to be_enabled_insync(:true)
509
+ end
510
+
511
+ it 'logs no debug messsage' do
512
+ expect(Puppet).not_to receive(:debug)
513
+ provider.enabled_insync?(:true)
514
+ end
470
515
  end
471
516
  end
472
517
 
@@ -271,4 +271,206 @@ describe 'Puppet::Type::Service::Provider::Windows',
271
271
  }.to raise_error(Puppet::Error, /Cannot enable #{name}/)
272
272
  end
273
273
  end
274
+
275
+ describe "when managing logon credentials" do
276
+ before do
277
+ allow(Puppet::Util::Windows::ADSI).to receive(:computer_name).and_return(computer_name)
278
+ allow(Puppet::Util::Windows::SID).to receive(:name_to_principal).and_return(principal)
279
+ allow(Puppet::Util::Windows::Service).to receive(:set_startup_configuration).and_return(nil)
280
+ end
281
+
282
+ let(:computer_name) { 'myPC' }
283
+
284
+ describe "#logonaccount=" do
285
+ before do
286
+ allow(Puppet::Util::Windows::User).to receive(:password_is?).and_return(true)
287
+ resource[:logonaccount] = user_input
288
+ provider.logonaccount_insync?(user_input)
289
+ end
290
+
291
+ let(:user_input) { principal.account }
292
+ let(:principal) do
293
+ Puppet::Util::Windows::SID::Principal.new("myUser", nil, nil, computer_name, :SidTypeUser)
294
+ end
295
+
296
+ context "when given user is 'myUser'" do
297
+ it "should fail when the `Log On As A Service` right is missing from given user" do
298
+ allow(Puppet::Util::Windows::User).to receive(:get_rights).with(principal.domain_account).and_return("")
299
+ expect { provider.logonaccount=(user_input) }.to raise_error(Puppet::Error, /".\\#{principal.account}" is missing the 'Log On As A Service' right./)
300
+ end
301
+
302
+ it "should fail when the `Log On As A Service` right is set to denied for given user" do
303
+ allow(Puppet::Util::Windows::User).to receive(:get_rights).with(principal.domain_account).and_return("SeDenyServiceLogonRight")
304
+ expect { provider.logonaccount=(user_input) }.to raise_error(Puppet::Error, /".\\#{principal.account}" has the 'Log On As A Service' right set to denied./)
305
+ end
306
+
307
+ it "should not fail when given user has the `Log On As A Service` right" do
308
+ allow(Puppet::Util::Windows::User).to receive(:get_rights).with(principal.domain_account).and_return("SeServiceLogonRight")
309
+ expect { provider.logonaccount=(user_input) }.not_to raise_error
310
+ end
311
+
312
+ ['myUser', 'myPC\\myUser', ".\\myUser", "MYPC\\mYuseR"].each do |user_input_variant|
313
+ let(:user_input) { user_input_variant }
314
+
315
+ it "should succesfully munge #{user_input_variant} to '.\\myUser'" do
316
+ allow(Puppet::Util::Windows::User).to receive(:get_rights).with(principal.domain_account).and_return("SeServiceLogonRight")
317
+ expect { provider.logonaccount=(user_input) }.not_to raise_error
318
+ expect(resource[:logonaccount]).to eq(".\\myUser")
319
+ end
320
+ end
321
+ end
322
+
323
+ context "when given user is a system account" do
324
+ before do
325
+ allow(Puppet::Util::Windows::User).to receive(:default_system_account?).and_return(true)
326
+ end
327
+
328
+ let(:user_input) { principal.account }
329
+ let(:principal) do
330
+ Puppet::Util::Windows::SID::Principal.new("LOCAL SERVICE", nil, nil, "NT AUTHORITY", :SidTypeUser)
331
+ end
332
+
333
+ it "should not fail when given user is a default system account even if the `Log On As A Service` right is missing" do
334
+ expect(Puppet::Util::Windows::User).not_to receive(:get_rights)
335
+ expect { provider.logonaccount=(user_input) }.not_to raise_error
336
+ end
337
+
338
+ ['LocalSystem', '.\LocalSystem', 'myPC\LocalSystem', 'lOcALsysTem'].each do |user_input_variant|
339
+ let(:user_input) { user_input_variant }
340
+
341
+ it "should succesfully munge #{user_input_variant} to 'LocalSystem'" do
342
+ expect { provider.logonaccount=(user_input) }.not_to raise_error
343
+ expect(resource[:logonaccount]).to eq('LocalSystem')
344
+ end
345
+ end
346
+ end
347
+
348
+ context "when domain is different from computer name" do
349
+ before do
350
+ allow(Puppet::Util::Windows::User).to receive(:get_rights).and_return("SeServiceLogonRight")
351
+ end
352
+
353
+ context "when given user is from AD" do
354
+ let(:user_input) { 'myRemoteUser' }
355
+ let(:principal) do
356
+ Puppet::Util::Windows::SID::Principal.new("myRemoteUser", nil, nil, "AD", :SidTypeUser)
357
+ end
358
+
359
+ it "should not raise any error" do
360
+ expect { provider.logonaccount=(user_input) }.not_to raise_error
361
+ end
362
+
363
+ it "should succesfully be munged" do
364
+ expect { provider.logonaccount=(user_input) }.not_to raise_error
365
+ expect(resource[:logonaccount]).to eq('AD\myRemoteUser')
366
+ end
367
+ end
368
+
369
+ context "when given user is LocalService" do
370
+ let(:user_input) { 'LocalService' }
371
+ let(:principal) do
372
+ Puppet::Util::Windows::SID::Principal.new("LOCAL SERVICE", nil, nil, "NT AUTHORITY", :SidTypeWellKnownGroup)
373
+ end
374
+
375
+ it "should succesfully munge well known user" do
376
+ expect { provider.logonaccount=(user_input) }.not_to raise_error
377
+ expect(resource[:logonaccount]).to eq('NT AUTHORITY\LOCAL SERVICE')
378
+ end
379
+ end
380
+
381
+ context "when given user is in SID form" do
382
+ let(:user_input) { 'S-1-5-20' }
383
+ let(:principal) do
384
+ Puppet::Util::Windows::SID::Principal.new("NETWORK SERVICE", nil, nil, "NT AUTHORITY", :SidTypeUser)
385
+ end
386
+
387
+ it "should succesfully munge" do
388
+ expect { provider.logonaccount=(user_input) }.not_to raise_error
389
+ expect(resource[:logonaccount]).to eq('NT AUTHORITY\NETWORK SERVICE')
390
+ end
391
+ end
392
+
393
+ context "when given user is actually a group" do
394
+ let(:principal) do
395
+ Puppet::Util::Windows::SID::Principal.new("Administrators", nil, nil, "BUILTIN", :SidTypeAlias)
396
+ end
397
+ let(:user_input) { 'Administrators' }
398
+
399
+ it "should fail when sid type is not user or well known user" do
400
+ expect { provider.logonaccount=(user_input) }.to raise_error(Puppet::Error, /"BUILTIN\\#{user_input}" is not a valid account/)
401
+ end
402
+ end
403
+ end
404
+ end
405
+
406
+ describe "#logonpassword=" do
407
+ before do
408
+ allow(Puppet::Util::Windows::User).to receive(:get_rights).and_return('SeServiceLogonRight')
409
+ resource[:logonaccount] = account
410
+ resource[:logonpassword] = user_input
411
+ provider.logonaccount_insync?(account)
412
+ end
413
+
414
+ let(:account) { 'LocalSystem' }
415
+
416
+ describe "when given logonaccount is a predefined_local_account" do
417
+ let(:user_input) { 'pass' }
418
+ let(:principal) { nil }
419
+
420
+ it "should pass validation when given account is 'LocalSystem'" do
421
+ allow(Puppet::Util::Windows::User).to receive(:localsystem?).with('LocalSystem').and_return(true)
422
+ allow(Puppet::Util::Windows::User).to receive(:default_system_account?).with('LocalSystem').and_return(true)
423
+
424
+ expect(Puppet::Util::Windows::User).not_to receive(:password_is?)
425
+ expect { provider.logonpassword=(user_input) }.not_to raise_error
426
+ end
427
+
428
+ ['LOCAL SERVICE', 'NETWORK SERVICE', 'SYSTEM'].each do |predefined_local_account|
429
+ describe "when given account is #{predefined_local_account}" do
430
+ let(:account) { 'predefined_local_account' }
431
+ let(:principal) do
432
+ Puppet::Util::Windows::SID::Principal.new(account, nil, nil, "NT AUTHORITY", :SidTypeUser)
433
+ end
434
+
435
+ it "should pass validation" do
436
+ allow(Puppet::Util::Windows::User).to receive(:localsystem?).with(principal.account).and_return(false)
437
+ allow(Puppet::Util::Windows::User).to receive(:localsystem?).with(principal.domain_account).and_return(false)
438
+ expect(Puppet::Util::Windows::User).to receive(:default_system_account?).with(principal.domain_account).and_return(true).twice
439
+
440
+ expect(Puppet::Util::Windows::User).not_to receive(:password_is?)
441
+ expect { provider.logonpassword=(user_input) }.not_to raise_error
442
+ end
443
+ end
444
+ end
445
+ end
446
+
447
+ describe "when given logonaccount is not a predefined local account" do
448
+ before do
449
+ allow(Puppet::Util::Windows::User).to receive(:localsystem?).with(".\\#{principal.account}").and_return(false)
450
+ allow(Puppet::Util::Windows::User).to receive(:default_system_account?).with(".\\#{principal.account}").and_return(false)
451
+ end
452
+
453
+ let(:account) { 'myUser' }
454
+ let(:principal) do
455
+ Puppet::Util::Windows::SID::Principal.new(account, nil, nil, computer_name, :SidTypeUser)
456
+ end
457
+
458
+ describe "when password is proven correct" do
459
+ let(:user_input) { 'myPass' }
460
+ it "should pass validation" do
461
+ allow(Puppet::Util::Windows::User).to receive(:password_is?).with('myUser', 'myPass', '.').and_return(true)
462
+ expect { provider.logonpassword=(user_input) }.not_to raise_error
463
+ end
464
+ end
465
+
466
+ describe "when password is not proven correct" do
467
+ let(:user_input) { 'myWrongPass' }
468
+ it "should not pass validation" do
469
+ allow(Puppet::Util::Windows::User).to receive(:password_is?).with('myUser', 'myWrongPass', '.').and_return(false)
470
+ expect { provider.logonpassword=(user_input) }.to raise_error(Puppet::Error, /The given password is invalid for user '.\\myUser'/)
471
+ end
472
+ end
473
+ end
474
+ end
475
+ end
274
476
  end
@@ -925,28 +925,75 @@ end
925
925
  }
926
926
  end
927
927
 
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)
934
930
  end
935
931
 
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
942
956
  end
943
957
 
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
950
997
  end
951
998
  end
952
999
 
@@ -974,16 +1021,7 @@ end
974
1021
  describe '#set_shadow_hash_data' do
975
1022
  let(:users_plist) { {'ShadowHashData' => ['string_data'] } }
976
1023
 
977
- it 'should flush the plist data to disk on OS X < 10.15' do
978
- allow(provider.class).to receive(:get_os_version).and_return('10.12')
979
-
980
- expect(provider).to receive(:write_users_plist_to_disk)
981
- provider.set_shadow_hash_data(users_plist, pbkdf2_embedded_plist)
982
- end
983
-
984
- it 'should flush the plist data a temporary file on OS X >= 10.15' do
985
- allow(provider.class).to receive(:get_os_version).and_return('10.15')
986
-
1024
+ it 'should flush the plist data to a temporary file' do
987
1025
  expect(provider).to receive(:write_and_import_shadow_hash_data)
988
1026
  provider.set_shadow_hash_data(users_plist, pbkdf2_embedded_plist)
989
1027
  end
@@ -1033,13 +1071,6 @@ end
1033
1071
  end
1034
1072
  end
1035
1073
 
1036
- describe '#write_users_plist_to_disk' do
1037
- it 'should save the passed plist to disk and convert it to a binary plist' do
1038
- expect(Puppet::Util::Plist).to receive(:write_plist_file).with(user_plist_xml, "#{users_plist_dir}/nonexistent_user.plist", :binary)
1039
- provider.write_users_plist_to_disk(user_plist_xml)
1040
- end
1041
- end
1042
-
1043
1074
  describe '#write_and_import_shadow_hash_data' do
1044
1075
  it 'should save the passed plist to a temporary file and import it' do
1045
1076
  tmpfile = double('tempfile', :path => "/tmp/dsimport_#{username}", :flush => nil)
@@ -1203,6 +1234,7 @@ end
1203
1234
  before :each do
1204
1235
  allow(provider.class).to receive(:get_all_users).and_return(all_users_hash)
1205
1236
  allow(provider.class).to receive(:get_list_of_groups).and_return(group_plist_hash_guid)
1237
+ allow(provider).to receive(:merge_attribute_with_dscl).with('Users', username, 'AuthenticationAuthority', any_args)
1206
1238
  provider.class.prefetch({})
1207
1239
  end
1208
1240