chef 14.6.47 → 14.7.17

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/chef-universal-mingw32.gemspec +1 -0
  3. data/lib/chef/application/apply.rb +6 -4
  4. data/lib/chef/knife/config_list_profiles.rb +1 -1
  5. data/lib/chef/knife/list.rb +1 -1
  6. data/lib/chef/knife/raw.rb +1 -1
  7. data/lib/chef/knife/role_env_run_list_clear.rb +1 -1
  8. data/lib/chef/knife/role_env_run_list_remove.rb +1 -1
  9. data/lib/chef/knife/role_env_run_list_replace.rb +1 -1
  10. data/lib/chef/knife/role_env_run_list_set.rb +1 -1
  11. data/lib/chef/knife/role_run_list_clear.rb +1 -1
  12. data/lib/chef/knife/role_run_list_remove.rb +1 -1
  13. data/lib/chef/knife/role_run_list_replace.rb +1 -1
  14. data/lib/chef/knife/role_run_list_set.rb +1 -1
  15. data/lib/chef/knife/show.rb +1 -1
  16. data/lib/chef/knife/upload.rb +1 -1
  17. data/lib/chef/knife/xargs.rb +1 -1
  18. data/lib/chef/node/attribute.rb +189 -185
  19. data/lib/chef/platform/rebooter.rb +1 -0
  20. data/lib/chef/property.rb +25 -1
  21. data/lib/chef/provider/windows_task.rb +19 -6
  22. data/lib/chef/resource.rb +17 -2
  23. data/lib/chef/resource/apt_preference.rb +2 -1
  24. data/lib/chef/resource/apt_repository.rb +1 -1
  25. data/lib/chef/resource/apt_update.rb +1 -0
  26. data/lib/chef/resource/build_essential.rb +1 -1
  27. data/lib/chef/resource/cab_package.rb +1 -1
  28. data/lib/chef/resource/chef_gem.rb +1 -1
  29. data/lib/chef/resource/cookbook_file.rb +2 -1
  30. data/lib/chef/resource/cron_d.rb +1 -1
  31. data/lib/chef/resource/dmg_package.rb +52 -40
  32. data/lib/chef/resource/execute.rb +2 -2
  33. data/lib/chef/resource/file.rb +1 -1
  34. data/lib/chef/resource/group.rb +2 -2
  35. data/lib/chef/resource/homebrew_cask.rb +3 -2
  36. data/lib/chef/resource/homebrew_tap.rb +2 -2
  37. data/lib/chef/resource/hostname.rb +2 -2
  38. data/lib/chef/resource/kernel_module.rb +19 -13
  39. data/lib/chef/resource/locale.rb +1 -0
  40. data/lib/chef/resource/macos_userdefaults.rb +7 -6
  41. data/lib/chef/resource/mdadm.rb +3 -2
  42. data/lib/chef/resource/mount.rb +3 -3
  43. data/lib/chef/resource/openssl_dhparam.rb +1 -1
  44. data/lib/chef/resource/openssl_ec_private_key.rb +1 -1
  45. data/lib/chef/resource/openssl_ec_public_key.rb +3 -3
  46. data/lib/chef/resource/openssl_rsa_private_key.rb +2 -2
  47. data/lib/chef/resource/openssl_rsa_public_key.rb +3 -3
  48. data/lib/chef/resource/openssl_x509_certificate.rb +1 -1
  49. data/lib/chef/resource/openssl_x509_crl.rb +1 -1
  50. data/lib/chef/resource/openssl_x509_request.rb +1 -1
  51. data/lib/chef/resource/package.rb +1 -1
  52. data/lib/chef/resource/powershell_package.rb +1 -1
  53. data/lib/chef/resource/remote_directory.rb +2 -2
  54. data/lib/chef/resource/rhsm_errata.rb +1 -1
  55. data/lib/chef/resource/rhsm_errata_level.rb +1 -1
  56. data/lib/chef/resource/rhsm_register.rb +7 -7
  57. data/lib/chef/resource/rhsm_repo.rb +1 -1
  58. data/lib/chef/resource/rhsm_subscription.rb +1 -1
  59. data/lib/chef/resource/sudo.rb +8 -8
  60. data/lib/chef/resource/swap_file.rb +1 -1
  61. data/lib/chef/resource/sysctl.rb +2 -2
  62. data/lib/chef/resource/systemd_unit.rb +19 -11
  63. data/lib/chef/resource/timezone.rb +60 -32
  64. data/lib/chef/resource/windows_ad_join.rb +1 -1
  65. data/lib/chef/resource/windows_auto_run.rb +1 -1
  66. data/lib/chef/resource/windows_certificate.rb +269 -0
  67. data/lib/chef/resource/windows_env.rb +12 -3
  68. data/lib/chef/resource/windows_feature.rb +6 -11
  69. data/lib/chef/resource/windows_feature_dism.rb +2 -2
  70. data/lib/chef/resource/windows_feature_powershell.rb +5 -9
  71. data/lib/chef/resource/windows_firewall_rule.rb +205 -0
  72. data/lib/chef/resource/windows_path.rb +3 -1
  73. data/lib/chef/resource/windows_printer.rb +2 -2
  74. data/lib/chef/resource/windows_printer_port.rb +3 -3
  75. data/lib/chef/resource/windows_service.rb +1 -0
  76. data/lib/chef/resource/windows_share.rb +315 -0
  77. data/lib/chef/resource/windows_task.rb +4 -0
  78. data/lib/chef/resource/windows_workgroup.rb +6 -4
  79. data/lib/chef/resource/yum_repository.rb +13 -7
  80. data/lib/chef/resource/zypper_package.rb +2 -2
  81. data/lib/chef/resource/zypper_repository.rb +2 -1
  82. data/lib/chef/resource_inspector.rb +4 -4
  83. data/lib/chef/resources.rb +3 -0
  84. data/lib/chef/version.rb +1 -1
  85. data/spec/functional/resource/windows_task_spec.rb +39 -0
  86. data/spec/support/platform_helpers.rb +2 -1
  87. data/spec/unit/resource/windows_certificate.rb +46 -0
  88. data/spec/unit/resource/windows_firewall_rule_spec.rb +401 -0
  89. data/spec/unit/resource/windows_share.rb +39 -0
  90. metadata +10 -4
@@ -37,17 +37,17 @@ class Chef
37
37
  # acording to the sudo man pages sudo will ignore files in an include dir that have a `.` or `~`
38
38
  # We convert either to `__`
39
39
  property :filename, String,
40
- description: "The name of the sudoers.d file.",
40
+ description: "The name of the sudoers.d file, if it differs from the name of the resource block",
41
41
  name_property: true,
42
42
  coerce: proc { |x| x.gsub(/[\.~]/, "__") }
43
43
 
44
44
  property :users, [String, Array],
45
- description: "User(s) to provide sudo privileges to. This accepts either an array or a comma separated.",
45
+ description: "User(s) to provide sudo privileges to. This property accepts either an array or a comma separated list.",
46
46
  default: lazy { [] },
47
47
  coerce: proc { |x| x.is_a?(Array) ? x : x.split(/\s*,\s*/) }
48
48
 
49
49
  property :groups, [String, Array],
50
- description: "Group(s) to provide sudo privileges to. This accepts either an array or a comma separated list. Leading % on group names is optional.",
50
+ description: "Group(s) to provide sudo privileges to. This property accepts either an array or a comma separated list. Leading % on group names is optional.",
51
51
  default: lazy { [] },
52
52
  coerce: proc { |x| coerce_groups(x) }
53
53
 
@@ -72,10 +72,10 @@ class Chef
72
72
  default: false
73
73
 
74
74
  property :template, String,
75
- description: "The name of the erb template in your cookbook if you wish to supply your own template."
75
+ description: "The name of the erb template in your cookbook, if you wish to supply your own template."
76
76
 
77
77
  property :variables, [Hash, nil],
78
- description: "The variables to pass to the custom template. Ignored if not using a custom template.",
78
+ description: "The variables to pass to the custom template. This property is ignored if not using a custom template.",
79
79
  default: nil
80
80
 
81
81
  property :defaults, Array,
@@ -99,15 +99,15 @@ class Chef
99
99
  default: lazy { [] }
100
100
 
101
101
  property :visudo_path, String,
102
- description: "Deprecated property. Do not use."
102
+ deprecated: true
103
103
 
104
104
  property :visudo_binary, String,
105
105
  description: "The path to visudo for configuration verification.",
106
106
  default: "/usr/sbin/visudo"
107
107
 
108
108
  property :config_prefix, String,
109
- description: "The directory that contains the sudoers configuration file",
110
- default: lazy { platform_config_prefix }
109
+ description: "The directory that contains the sudoers configuration file.",
110
+ default: lazy { platform_config_prefix }, default_description: "Prefix values based on the node's platform"
111
111
 
112
112
  # handle legacy cookbook property
113
113
  def after_created
@@ -27,7 +27,7 @@ class Chef
27
27
  introduced "14.0"
28
28
 
29
29
  property :path, String,
30
- description: "The path to put the swap file on the system.",
30
+ description: "The path where the swap file will be created on the system, if it differs from the resource block name.",
31
31
  name_property: true
32
32
 
33
33
  property :size, Integer,
@@ -24,7 +24,7 @@ class Chef
24
24
  provides(:sysctl) { true }
25
25
  provides(:sysctl_param) { true }
26
26
 
27
- description "Use the sysctl resource to set kernel parameters using the sysctl"\
27
+ description "Use the sysctl resource to set or remove kernel parameters using the sysctl"\
28
28
  " command line tool and configuration files in the system's sysctl.d directory. "\
29
29
  "Configuration files managed by this resource are named 99-chef-KEYNAME.conf. If"\
30
30
  " an existing value was already set for the value it will be backed up to the node"\
@@ -33,7 +33,7 @@ class Chef
33
33
  introduced "14.0"
34
34
 
35
35
  property :key, String,
36
- description: "The kernel parameter key in dotted format.",
36
+ description: "The kernel parameter key in dotted format, if it differs from the resource block name.",
37
37
  name_property: true
38
38
 
39
39
  property :ignore_error, [TrueClass, FalseClass],
@@ -38,22 +38,30 @@ class Chef
38
38
  :reload_or_try_restart
39
39
 
40
40
  # Internal provider-managed properties
41
- property :enabled, [TrueClass, FalseClass]
42
- property :active, [TrueClass, FalseClass]
43
- property :masked, [TrueClass, FalseClass]
44
- property :static, [TrueClass, FalseClass]
41
+ property :enabled, [TrueClass, FalseClass], skip_docs: true
42
+ property :active, [TrueClass, FalseClass], skip_docs: true
43
+ property :masked, [TrueClass, FalseClass], skip_docs: true
44
+ property :static, [TrueClass, FalseClass], skip_docs: true
45
45
 
46
46
  # User-provided properties
47
- property :user, String, desired_state: false
48
- property :content, [String, Hash]
47
+ property :user, String, desired_state: false,
48
+ description: "The user account that the systemd unit process is run under. The path to the unit for that user would be something like '/etc/systemd/user/sshd.service'. If no user account is specified, the systemd unit will run under a 'system' account, with the path to the unit being something like '/etc/systemd/system/sshd.service'."
49
+
50
+ property :content, [String, Hash],
51
+ description: "A string or hash that contains a systemd `unit file <https://www.freedesktop.org/software/systemd/man/systemd.unit.html>`_ definition that describes the properties of systemd-managed entities, such as services, sockets, devices, and so on. In Chef 14.4 or later, repeatable options can be implemented with an array."
52
+
49
53
  property :triggers_reload, [TrueClass, FalseClass],
50
- default: true, desired_state: false
54
+ description: "Specifies whether to trigger a daemon reload when creating or deleting a unit.",
55
+ default: true, desired_state: false
56
+
51
57
  property :verify, [TrueClass, FalseClass],
52
- default: true, desired_state: false
58
+ default: true, desired_state: false,
59
+ description: "Specifies if the unit will be verified before installation. Systemd can be overly strict when verifying units, so in certain cases it is preferable not to verify the unit."
60
+
53
61
  property :unit_name, String, desired_state: false,
54
- identity: true,
55
- name_property: true,
56
- introduced: "13.7"
62
+ identity: true, name_property: true,
63
+ description: "The name of the unit file if it differs from the resource block name.",
64
+ introduced: "13.7"
57
65
 
58
66
  def to_ini
59
67
  case content
@@ -25,7 +25,7 @@ class Chef
25
25
  preview_resource true
26
26
  resource_name :timezone
27
27
 
28
- description "Use the timezone resource to change the system timezone."
28
+ description "Use the timezone resource to change the system timezone on Linux and macOS hosts. Timezones are specified in tz database format, with a complete list of available TZ values here https://en.wikipedia.org/wiki/List_of_tz_database_time_zones."
29
29
  introduced "14.6"
30
30
 
31
31
  property :timezone, String,
@@ -35,12 +35,15 @@ class Chef
35
35
  action :set do
36
36
  description "Set the timezone."
37
37
 
38
- package "tzdata" do
39
- package_name platform_family?("suse") ? "timezone" : "tzdata"
38
+ # some linux systems may be missing the timezone data
39
+ if node["os"] == "linux"
40
+ package "tzdata" do
41
+ package_name platform_family?("suse") ? "timezone" : "tzdata"
42
+ end
40
43
  end
41
44
 
45
+ # Modern Amazon, Fedora, RHEL, Ubuntu & Debian
42
46
  if node["init_package"] == "systemd"
43
- # Modern Amazon, Fedora, CentOS, RHEL, Ubuntu & Debian
44
47
  cmd_set_tz = "/usr/bin/timedatectl --no-ask-password set-timezone #{new_resource.timezone}"
45
48
 
46
49
  cmd_check_if_set = "/usr/bin/timedatectl status"
@@ -51,38 +54,63 @@ class Chef
51
54
  action :run
52
55
  not_if cmd_check_if_set
53
56
  end
54
- elsif platform_family?("rhel", "amazon")
55
- # Old version of RHEL & CentOS
56
- file "/etc/sysconfig/clock" do
57
- owner "root"
58
- group "root"
59
- mode "0644"
60
- action :create
61
- content %{ZONE="#{new_resource.timezone}"\nUTC="true"\n}
62
- end
57
+ else
58
+ case node["platform_family"]
59
+ # Old version of RHEL < 7 and Amazon 201X
60
+ when "rhel", "amazon"
61
+ file "/etc/sysconfig/clock" do
62
+ owner "root"
63
+ group "root"
64
+ mode "0644"
65
+ action :create
66
+ content %{ZONE="#{new_resource.timezone}"\nUTC="true"\n}
67
+ end
63
68
 
64
- execute "tzdata-update" do
65
- command "/usr/sbin/tzdata-update"
66
- action :nothing
67
- only_if { ::File.executable?("/usr/sbin/tzdata-update") }
68
- subscribes :run, "file[/etc/sysconfig/clock]", :immediately
69
- end
69
+ execute "tzdata-update" do
70
+ command "/usr/sbin/tzdata-update"
71
+ action :nothing
72
+ only_if { ::File.executable?("/usr/sbin/tzdata-update") }
73
+ subscribes :run, "file[/etc/sysconfig/clock]", :immediately
74
+ end
70
75
 
71
- link "/etc/localtime" do
72
- to "/usr/share/zoneinfo/#{new_resource.timezone}"
73
- not_if { ::File.executable?("/usr/sbin/tzdata-update") }
74
- end
75
- elsif platform_family?("debian")
76
- file "/etc/timezone" do
77
- action :create
78
- content "#{new_resource.timezone}\n"
76
+ link "/etc/localtime" do
77
+ to "/usr/share/zoneinfo/#{new_resource.timezone}"
78
+ not_if { ::File.executable?("/usr/sbin/tzdata-update") }
79
+ end
80
+ # debian < 8 and Ubuntu < 16.04
81
+ when "debian"
82
+ file "/etc/timezone" do
83
+ action :create
84
+ content "#{new_resource.timezone}\n"
85
+ end
86
+
87
+ bash "dpkg-reconfigure tzdata" do
88
+ user "root"
89
+ code "/usr/sbin/dpkg-reconfigure -f noninteractive tzdata"
90
+ action :nothing
91
+ subscribes :run, "file[/etc/timezone]", :immediately
92
+ end
93
+ when "mac_os_x"
94
+ unless current_darwin_tz == new_resource.timezone
95
+ converge_by("set timezone to #{new_resource.timezone}") do
96
+ shell_out!("sudo systemsetup -settimezone #{new_resource.timezone}")
97
+ end
98
+ end
79
99
  end
100
+ end
101
+ end
80
102
 
81
- bash "dpkg-reconfigure tzdata" do
82
- user "root"
83
- code "/usr/sbin/dpkg-reconfigure -f noninteractive tzdata"
84
- action :nothing
85
- subscribes :run, "file[/etc/timezone]", :immediately
103
+ action_class do
104
+ # detect the current TZ on darwin hosts
105
+ #
106
+ # @since 14.7
107
+ # @return [String] TZ database value
108
+ def current_darwin_tz
109
+ tz_shellout = shell_out!("systemsetup -gettimezone")
110
+ if /You need administrator access/.match?(tz_shellout.stdout)
111
+ raise "The timezone resource requires adminstrative priveleges to run on macOS hosts!"
112
+ else
113
+ /Time Zone: (.*)/.match(tz_shellout.stdout)[1]
86
114
  end
87
115
  end
88
116
  end
@@ -58,7 +58,7 @@ class Chef
58
58
 
59
59
  # define this again so we can default it to true. Otherwise failures print the password
60
60
  property :sensitive, [TrueClass, FalseClass],
61
- default: true
61
+ default: true, desired_state: false
62
62
 
63
63
  action :join do
64
64
  description "Join the Active Directory domain."
@@ -28,7 +28,7 @@ class Chef
28
28
  introduced "14.0"
29
29
 
30
30
  property :program_name, String,
31
- description: "The name of the program to run at login if different from the resource name.",
31
+ description: "The name of the program to run at login, if it differs from the resource block name.",
32
32
  name_property: true
33
33
 
34
34
  property :path, String,
@@ -0,0 +1,269 @@
1
+ #
2
+ # Author:: Richard Lavey (richard.lavey@calastone.com)
3
+ #
4
+ # Copyright:: 2015-2017, Calastone Ltd.
5
+ # Copyright:: 2018, Chef Software, Inc.
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+
20
+ require "chef/resource"
21
+ require "win32-certstore" if Chef::Platform.windows?
22
+ require "openssl"
23
+
24
+ class Chef
25
+ class Resource
26
+ class WindowsCertificate < Chef::Resource
27
+ preview_resource true
28
+ resource_name :windows_certificate
29
+
30
+ description "Use the windows_certificate resource to install a certificate into the Windows certificate store from a file. The resource grants read-only access to the private key for designated accounts. Due to current limitations in WinRM, installing certificates remotely may not work if the operation requires a user profile. Operations on the local machine store should still work."
31
+ introduced "14.7"
32
+
33
+ property :source, String,
34
+ description: "The source file (for create and acl_add), thumbprint (for delete and acl_add) or subject (for delete).",
35
+ name_property: true
36
+
37
+ property :pfx_password, String,
38
+ description: "The password to access the source if it is a pfx file."
39
+
40
+ property :private_key_acl, Array,
41
+ description: "An array of 'domain\account' entries to be granted read-only access to the certificate's private key. Not idempotent."
42
+
43
+ property :store_name, String,
44
+ description: "The certificate store to manipulate.",
45
+ default: "MY", equal_to: ["TRUSTEDPUBLISHER", "TrustedPublisher", "CLIENTAUTHISSUER", "REMOTE DESKTOP", "ROOT", "TRUSTEDDEVICES", "WEBHOSTING", "CA", "AUTHROOT", "TRUSTEDPEOPLE", "MY", "SMARTCARDROOT", "TRUST", "DISALLOWED"]
46
+
47
+ property :user_store, [TrueClass, FalseClass],
48
+ description: "Use the user store of the local machine store if set to false.",
49
+ default: false
50
+
51
+ property :cert_path, String,
52
+ description: ""
53
+
54
+ # lazy used to set default value of sensitive to true if password is set
55
+ property :sensitive, [ TrueClass, FalseClass ],
56
+ description: "Ensure that sensitive resource data is not logged by the chef-client.",
57
+ default: lazy { |r| r.pfx_password ? true : false }, skip_docs: true
58
+
59
+ action :create do
60
+ description "Creates or updates a certificate."
61
+
62
+ add_cert(OpenSSL::X509::Certificate.new(raw_source))
63
+ end
64
+
65
+ # acl_add is a modify-if-exists operation : not idempotent
66
+ action :acl_add do
67
+ description "Adds read-only entries to a certificate's private key ACL."
68
+
69
+ if ::File.exist?(new_resource.source)
70
+ hash = "$cert.GetCertHashString()"
71
+ code_script = cert_script(false)
72
+ guard_script = cert_script(false)
73
+ else
74
+ # make sure we have no spaces in the hash string
75
+ hash = "\"#{new_resource.source.gsub(/\s/, '')}\""
76
+ code_script = ""
77
+ guard_script = ""
78
+ end
79
+ code_script << acl_script(hash)
80
+ guard_script << cert_exists_script(hash)
81
+
82
+ powershell_script "setting the acls on #{new_resource.source} in #{cert_location}\\#{new_resource.store_name}" do
83
+ guard_interpreter :powershell_script
84
+ convert_boolean_return true
85
+ code code_script
86
+ only_if guard_script
87
+ sensitive if new_resource.sensitive
88
+ end
89
+ end
90
+
91
+ action :delete do
92
+ description "Deletes a certificate."
93
+
94
+ delete_cert
95
+ end
96
+
97
+ action :fetch do
98
+ description "Fetches a certificate."
99
+
100
+ cert_obj = fetch_cert
101
+ if cert_obj
102
+ show_or_store_cert(cert_obj)
103
+ else
104
+ Chef::Log.info("Certificate not found")
105
+ end
106
+ end
107
+
108
+ action :verify do
109
+ description ""
110
+
111
+ out = verify_cert
112
+ if !!out == out
113
+ out = out ? "Certificate is valid" : "Certificate not valid"
114
+ end
115
+ Chef::Log.info(out.to_s)
116
+ end
117
+
118
+ action_class do
119
+ def add_cert(cert_obj)
120
+ store = ::Win32::Certstore.open(new_resource.store_name)
121
+ store.add(cert_obj)
122
+ end
123
+
124
+ def delete_cert
125
+ store = ::Win32::Certstore.open(new_resource.store_name)
126
+ store.delete(new_resource.source)
127
+ end
128
+
129
+ def fetch_cert
130
+ store = ::Win32::Certstore.open(new_resource.store_name)
131
+ store.get(new_resource.source)
132
+ end
133
+
134
+ def verify_cert
135
+ store = ::Win32::Certstore.open(new_resource.store_name)
136
+ store.valid?(new_resource.source)
137
+ end
138
+
139
+ def show_or_store_cert(cert_obj)
140
+ if new_resource.cert_path
141
+ export_cert(cert_obj, new_resource.cert_path)
142
+ if ::File.size(new_resource.cert_path) > 0
143
+ Chef::Log.info("Certificate export in #{new_resource.cert_path}")
144
+ else
145
+ ::File.delete(new_resource.cert_path)
146
+ end
147
+ else
148
+ Chef::Log.info(cert_obj.display)
149
+ end
150
+ end
151
+
152
+ def export_cert(cert_obj, cert_path)
153
+ out_file = ::File.new(cert_path, "w+")
154
+ case ::File.extname(cert_path)
155
+ when ".pem"
156
+ out_file.puts(cert_obj.to_pem)
157
+ when ".der"
158
+ out_file.puts(cert_obj.to_der)
159
+ when ".cer"
160
+ cert_out = powershell_out("openssl x509 -text -inform DER -in #{cert_obj.to_pem} -outform CER").stdout
161
+ out_file.puts(cert_out)
162
+ when ".crt"
163
+ cert_out = powershell_out("openssl x509 -text -inform DER -in #{cert_obj.to_pem} -outform CRT").stdout
164
+ out_file.puts(cert_out)
165
+ when ".pfx"
166
+ cert_out = powershell_out("openssl pkcs12 -export -nokeys -in #{cert_obj.to_pem} -outform PFX").stdout
167
+ out_file.puts(cert_out)
168
+ when ".p7b"
169
+ cert_out = powershell_out("openssl pkcs7 -export -nokeys -in #{cert_obj.to_pem} -outform P7B").stdout
170
+ out_file.puts(cert_out)
171
+ else
172
+ Chef::Log.info("Supported certificate format .pem, .der, .cer, .crt, .pfx and .p7b")
173
+ end
174
+ out_file.close
175
+ end
176
+
177
+ def cert_location
178
+ @location ||= new_resource.user_store ? "CurrentUser" : "LocalMachine"
179
+ end
180
+
181
+ def cert_script(persist)
182
+ cert_script = "$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2"
183
+ file = win_friendly_path(new_resource.source)
184
+ cert_script << " \"#{file}\""
185
+ if ::File.extname(file.downcase) == ".pfx"
186
+ cert_script << ", \"#{new_resource.pfx_password}\""
187
+ if persist && new_resource.user_store
188
+ cert_script << ", ([System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::PersistKeySet)"
189
+ elsif persist
190
+ cert_script << ", ([System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::PersistKeySet -bor [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::MachineKeyset)"
191
+ end
192
+ end
193
+ cert_script << "\n"
194
+ end
195
+
196
+ def cert_exists_script(hash)
197
+ <<-EOH
198
+ $hash = #{hash}
199
+ Test-Path "Cert:\\#{cert_location}\\#{new_resource.store_name}\\$hash"
200
+ EOH
201
+ end
202
+
203
+ def within_store_script
204
+ inner_script = yield "$store"
205
+ <<-EOH
206
+ $store = New-Object System.Security.Cryptography.X509Certificates.X509Store "#{new_resource.store_name}", ([System.Security.Cryptography.X509Certificates.StoreLocation]::#{cert_location})
207
+ $store.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadWrite)
208
+ #{inner_script}
209
+ $store.Close()
210
+ EOH
211
+ end
212
+
213
+ def acl_script(hash)
214
+ return "" if new_resource.private_key_acl.nil? || new_resource.private_key_acl.empty?
215
+ # this PS came from http://blogs.technet.com/b/operationsguy/archive/2010/11/29/provide-access-to-private-keys-commandline-vs-powershell.aspx
216
+ # and from https://msdn.microsoft.com/en-us/library/windows/desktop/bb204778(v=vs.85).aspx
217
+ set_acl_script = <<-EOH
218
+ $hash = #{hash}
219
+ $storeCert = Get-ChildItem "cert:\\#{cert_location}\\#{new_resource.store_name}\\$hash"
220
+ if ($storeCert -eq $null) { throw 'no key exists.' }
221
+ $keyname = $storeCert.PrivateKey.CspKeyContainerInfo.UniqueKeyContainerName
222
+ if ($keyname -eq $null) { throw 'no private key exists.' }
223
+ if ($storeCert.PrivateKey.CspKeyContainerInfo.MachineKeyStore)
224
+ {
225
+ $fullpath = "$Env:ProgramData\\Microsoft\\Crypto\\RSA\\MachineKeys\\$keyname"
226
+ }
227
+ else
228
+ {
229
+ $currentUser = New-Object System.Security.Principal.NTAccount($Env:UserDomain, $Env:UserName)
230
+ $userSID = $currentUser.Translate([System.Security.Principal.SecurityIdentifier]).Value
231
+ $fullpath = "$Env:ProgramData\\Microsoft\\Crypto\\RSA\\$userSID\\$keyname"
232
+ }
233
+ EOH
234
+ new_resource.private_key_acl.each do |name|
235
+ set_acl_script << "$uname='#{name}'; icacls $fullpath /grant $uname`:RX\n"
236
+ end
237
+ set_acl_script
238
+ end
239
+
240
+ def raw_source
241
+ ext = ::File.extname(new_resource.source)
242
+ convert_pem(ext, new_resource.source)
243
+ end
244
+
245
+ def convert_pem(ext, source)
246
+ out = case ext
247
+ when ".crt", ".der"
248
+ powershell_out("openssl x509 -text -inform DER -in #{source} -outform PEM").stdout
249
+ when ".cer"
250
+ powershell_out("openssl x509 -text -inform DER -in #{source} -outform PEM").stdout
251
+ when ".pfx"
252
+ powershell_out("openssl pkcs12 -in #{source} -nodes -passin pass:#{new_resource.pfx_password}").stdout
253
+ when ".p7b"
254
+ powershell_out("openssl pkcs7 -print_certs -in #{source} -outform PEM").stdout
255
+ end
256
+ out = ::File.read(source) if out.nil? || out.empty?
257
+ format_raw_out(out)
258
+ end
259
+
260
+ def format_raw_out(out)
261
+ begin_cert = "-----BEGIN CERTIFICATE-----"
262
+ end_cert = "-----END CERTIFICATE-----"
263
+ begin_cert + out[/#{begin_cert}(.*?)#{end_cert}/m, 1] + end_cert
264
+ end
265
+ end
266
+
267
+ end
268
+ end
269
+ end