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 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
|
# frozen_string_literal: true
Puppet::Type.newtype(:java_ks) do
@doc = 'Manages the entries in a java keystore, and uses composite namevars to
accomplish the same alias spread across multiple target keystores.'
ensurable do
desc 'Has three states: present, absent, and latest. Latest
will compare the on disk SHA1 fingerprint of the certificate to that
in keytool to determine if insync? returns true or false. We redefine
insync? for this parameter to accomplish this.'
newvalue(:present) do
provider.create
end
newvalue(:absent) do
provider.destroy
end
newvalue(:latest) do
if provider.exists?
provider.update
else
provider.create
end
end
def insync?(is)
@should.each do |should|
case should
when :present
return true if is == :present
when :absent
return true if is == :absent
when :latest
unless is == :absent
current = provider.current.split('/')
latest = provider.latest.split('/')
return true if latest.to_set.subset?(current.to_set)
end
end
end
false
end
defaultto :present
end
newparam(:name) do
desc 'The alias that is used to identify the entry in the keystore. This will be
converted to lowercase.'
isnamevar
munge(&:downcase)
end
newparam(:target) do
desc 'Destination file for the keystore. This will autorequire the parent directory of the file.'
isnamevar
end
newparam(:certificate) do
desc 'A file containing a server certificate, followed by zero or more intermediate certificate authorities.
All certificates will be placed in the keystore. This will autorequire the specified file.'
end
newparam(:certificate_content) do
desc 'A string containing a server certificate, followed by zero or more intermediate certificate authorities.
All certificates will be placed in the keystore.'
end
newparam(:storetype) do
desc 'Optional storetype
Valid options: <jceks>, <pkcs12>, <jks>'
newvalues(:jceks, :pkcs12, :jks)
end
newparam(:private_key) do
desc 'If you want an application to be a server and encrypt traffic,
you will need a private key. Private key entries in a keystore must be
accompanied by a signed certificate for the keytool provider. This parameter
allows you to specify the file name containing the private key. This will autorequire
the specified file.'
end
newparam(:private_key_content) do
desc 'If you want an application to be a server and encrypt traffic,
you will need a private key. Private key entries in a keystore must be
accompanied by a signed certificate for the keytool provider. This parameter allows you to specify the content
of the private key.'
end
newparam(:private_key_type) do
desc 'The type of the private key. Usually the private key is of type RSA
key but it can also be an Elliptic Curve key (EC) or DSA.
Valid options: <rsa>, <dsa>, <ec>. Defaults to <rsa>'
newvalues(:rsa, :dsa, :ec)
defaultto :rsa
end
newparam(:chain) do
desc 'The intermediate certificate authorities, if they are to be taken
from a file separate from the server certificate. This will autorequire the specified file.'
end
newproperty(:password) do
desc 'The password used to protect the keystore. If private keys are
subsequently also protected this password will be used to attempt
unlocking. Must be six or more characters in length. Cannot be used
together with :password_file, but you must pass at least one of these parameters.'
munge do |value|
value = value.unwrap if value.respond_to?(:unwrap)
super(value)
end
validate do |value|
value = value.unwrap if value.respond_to?(:unwrap)
raise Puppet::Error, "password is #{value.length} characters long; must be 6 characters or greater in length" if value.length < 6
end
end
newparam(:password_file) do
desc 'The path to a file containing the password used to protect the
keystore. This cannot be used together with :password, but you must pass at least one of these parameters.'
end
newparam(:password_fail_reset) do
desc "If the supplied password does not succeed in unlocking the
keystore file, then delete the keystore file and create a new one.
Default: false."
newvalues(true, false)
defaultto false
end
newparam(:destkeypass) do
desc 'The password used to protect the key in keystore.'
munge do |value|
value = value.unwrap if value.respond_to?(:unwrap)
super(value)
end
validate do |value|
value = value.unwrap if value.respond_to?(:unwrap)
raise Puppet::Error, "destkeypass is #{value.length} characters long; must be of length 6 or greater" if value.length < 6
end
end
newparam(:trustcacerts) do
desc "Certificate authorities aren't by default trusted so if you are adding a CA you need to set this to true.
Defaults to :false."
newvalues(true, false)
defaultto false
end
newparam(:path) do
desc "The search path used for command (keytool, openssl) execution.
Paths can be specified as an array or as a '#{File::PATH_SEPARATOR}' separated list."
# Support both arrays and colon-separated fields.
def value=(*values)
@value = values.flatten.map { |val|
val.split(File::PATH_SEPARATOR)
}.flatten
end
end
newparam(:keytool_timeout) do
desc 'Timeout for the keytool command in seconds.'
defaultto 120
end
newparam(:source_password) do
munge do |value|
value = value.unwrap if value.respond_to?(:unwrap)
super(value)
end
desc 'The source keystore password'
end
newparam(:source_alias) do
desc 'The source certificate alias'
end
# Where we setup autorequires.
autorequire(:file) do
auto_requires = []
[:private_key, :certificate, :chain].each do |param|
auto_requires << @parameters[param].value if @parameters.include?(param)
end
auto_requires << File.dirname(@parameters[:target].value) if @parameters.include?(:target)
auto_requires
end
# Our title_patterns method for mapping titles to namevars for supporting
# composite namevars.
def self.title_patterns
[
[
%r{^([^:]+)$},
[
[:name],
],
],
[
%r{^(.*):([a-z]:(/|\\).*)$}i,
[
[:name],
[:target],
],
],
[
%r{^(.*):(.*)$},
[
[:name],
[:target],
],
],
]
end
validate do
if self[:ensure] != :absent
raise Puppet::Error, "You must pass one of 'certificate' or 'certificate_content'" unless value(:certificate) || value(:certificate_content)
raise Puppet::Error, "You must pass either 'certificate' or 'certificate_content', not both." if value(:certificate) && value(:certificate_content)
raise Puppet::Error, "You must pass either 'private_key' or 'private_key_content', not both." if value(:private_key) && value(:private_key_content)
end
raise Puppet::Error, "You must pass either 'password' or 'password_file', not both." if value(:password) && value(:password_file)
raise Puppet::Error, "You must pass one of 'password' or 'password_file'." unless value(:password) || value(:password_file)
if value(:storetype) == :pkcs12 && value(:source_password).nil?
fail "You must provide 'source_password' when using a 'pkcs12' storetype." # rubocop:disable Style/SignalException : Associated test fails if 'raise' is used
end
end
end
|