puppet 2.7.5 → 2.7.6

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 (140) hide show
  1. data/CHANGELOG +121 -0
  2. data/conf/redhat/puppet.spec +16 -7
  3. data/lib/puppet.rb +1 -1
  4. data/lib/puppet/application/cert.rb +17 -3
  5. data/lib/puppet/application/device.rb +1 -0
  6. data/lib/puppet/application/kick.rb +0 -2
  7. data/lib/puppet/application/resource.rb +73 -66
  8. data/lib/puppet/configurer/plugin_handler.rb +6 -2
  9. data/lib/puppet/defaults.rb +60 -5
  10. data/lib/puppet/face/ca.rb +11 -2
  11. data/lib/puppet/face/certificate.rb +33 -4
  12. data/lib/puppet/file_serving/fileset.rb +1 -1
  13. data/lib/puppet/file_serving/indirection_hooks.rb +2 -2
  14. data/lib/puppet/file_serving/metadata.rb +43 -4
  15. data/lib/puppet/indirector.rb +0 -1
  16. data/lib/puppet/indirector/request.rb +3 -4
  17. data/lib/puppet/indirector/resource/active_record.rb +3 -10
  18. data/lib/puppet/indirector/resource/ral.rb +2 -2
  19. data/lib/puppet/indirector/rest.rb +1 -1
  20. data/lib/puppet/network/handler/ca.rb +16 -106
  21. data/lib/puppet/network/handler/master.rb +0 -3
  22. data/lib/puppet/network/handler/runner.rb +1 -0
  23. data/lib/puppet/parser/scope.rb +10 -0
  24. data/lib/puppet/provider/file/posix.rb +72 -34
  25. data/lib/puppet/provider/file/windows.rb +100 -0
  26. data/lib/puppet/provider/group/windows_adsi.rb +2 -2
  27. data/lib/puppet/provider/user/windows_adsi.rb +19 -4
  28. data/lib/puppet/resource.rb +16 -0
  29. data/lib/puppet/resource/catalog.rb +1 -1
  30. data/lib/puppet/ssl/certificate.rb +2 -2
  31. data/lib/puppet/ssl/certificate_authority.rb +86 -10
  32. data/lib/puppet/ssl/certificate_authority/interface.rb +64 -19
  33. data/lib/puppet/ssl/certificate_factory.rb +112 -91
  34. data/lib/puppet/ssl/certificate_request.rb +88 -1
  35. data/lib/puppet/ssl/host.rb +20 -3
  36. data/lib/puppet/type/file.rb +15 -34
  37. data/lib/puppet/type/file/group.rb +11 -91
  38. data/lib/puppet/type/file/mode.rb +11 -41
  39. data/lib/puppet/type/file/owner.rb +18 -34
  40. data/lib/puppet/type/file/source.rb +22 -7
  41. data/lib/puppet/type/group.rb +4 -3
  42. data/lib/puppet/type/user.rb +4 -1
  43. data/lib/puppet/util.rb +59 -6
  44. data/lib/puppet/util/adsi.rb +11 -0
  45. data/lib/puppet/util/log.rb +4 -0
  46. data/lib/puppet/util/log/destinations.rb +7 -1
  47. data/lib/puppet/util/monkey_patches.rb +19 -0
  48. data/lib/puppet/util/network_device/config.rb +4 -5
  49. data/lib/puppet/util/settings.rb +5 -0
  50. data/lib/puppet/util/suidmanager.rb +0 -1
  51. data/lib/puppet/util/windows.rb +4 -0
  52. data/lib/puppet/util/windows/error.rb +16 -0
  53. data/lib/puppet/util/windows/security.rb +593 -0
  54. data/spec/integration/defaults_spec.rb +27 -0
  55. data/spec/integration/network/handler_spec.rb +1 -1
  56. data/spec/integration/type/file_spec.rb +382 -145
  57. data/spec/integration/util/windows/security_spec.rb +468 -0
  58. data/spec/shared_behaviours/file_serving.rb +4 -3
  59. data/spec/unit/application/agent_spec.rb +1 -0
  60. data/spec/unit/application/device_spec.rb +5 -0
  61. data/spec/unit/application/resource_spec.rb +62 -101
  62. data/spec/unit/configurer/downloader_spec.rb +2 -2
  63. data/spec/unit/configurer/plugin_handler_spec.rb +15 -8
  64. data/spec/unit/configurer_spec.rb +2 -2
  65. data/spec/unit/face/ca_spec.rb +34 -0
  66. data/spec/unit/face/certificate_spec.rb +168 -1
  67. data/spec/unit/file_serving/fileset_spec.rb +1 -1
  68. data/spec/unit/file_serving/indirection_hooks_spec.rb +1 -1
  69. data/spec/unit/file_serving/metadata_spec.rb +151 -107
  70. data/spec/unit/indirector/certificate_request/ca_spec.rb +0 -3
  71. data/spec/unit/indirector/direct_file_server_spec.rb +10 -9
  72. data/spec/unit/indirector/file_metadata/file_spec.rb +6 -4
  73. data/spec/unit/indirector/request_spec.rb +13 -3
  74. data/spec/unit/indirector/resource/active_record_spec.rb +4 -10
  75. data/spec/unit/indirector/resource/ral_spec.rb +6 -4
  76. data/spec/unit/indirector/rest_spec.rb +5 -6
  77. data/spec/unit/network/handler/ca_spec.rb +86 -0
  78. data/spec/unit/parser/collector_spec.rb +7 -7
  79. data/spec/unit/parser/scope_spec.rb +20 -0
  80. data/spec/unit/provider/file/posix_spec.rb +226 -0
  81. data/spec/unit/provider/file/windows_spec.rb +136 -0
  82. data/spec/unit/provider/group/windows_adsi_spec.rb +7 -2
  83. data/spec/unit/provider/user/windows_adsi_spec.rb +36 -3
  84. data/spec/unit/resource/catalog_spec.rb +20 -10
  85. data/spec/unit/resource_spec.rb +55 -8
  86. data/spec/unit/ssl/certificate_authority/interface_spec.rb +97 -54
  87. data/spec/unit/ssl/certificate_authority_spec.rb +133 -23
  88. data/spec/unit/ssl/certificate_factory_spec.rb +90 -70
  89. data/spec/unit/ssl/certificate_request_spec.rb +62 -1
  90. data/spec/unit/ssl/certificate_spec.rb +20 -14
  91. data/spec/unit/ssl/host_spec.rb +52 -6
  92. data/spec/unit/type/file/content_spec.rb +4 -4
  93. data/spec/unit/type/file/group_spec.rb +34 -96
  94. data/spec/unit/type/file/mode_spec.rb +88 -0
  95. data/spec/unit/type/file/owner_spec.rb +32 -123
  96. data/spec/unit/type/file/source_spec.rb +120 -41
  97. data/spec/unit/type/file_spec.rb +1033 -753
  98. data/spec/unit/type_spec.rb +19 -1
  99. data/spec/unit/util/adsi_spec.rb +19 -0
  100. data/spec/unit/util/log/destinations_spec.rb +75 -0
  101. data/spec/unit/util/log_spec.rb +15 -0
  102. data/spec/unit/util/network_device/config_spec.rb +7 -0
  103. data/spec/unit/util/settings_spec.rb +10 -0
  104. data/spec/unit/util_spec.rb +126 -13
  105. data/test/language/functions.rb +0 -1
  106. data/test/language/snippets.rb +0 -9
  107. data/test/lib/puppettest/exetest.rb +1 -1
  108. data/test/lib/puppettest/servertest.rb +0 -1
  109. data/test/rails/rails.rb +0 -1
  110. data/test/ral/type/filesources.rb +0 -60
  111. metadata +13 -33
  112. data/lib/puppet/network/client.rb +0 -174
  113. data/lib/puppet/network/client/ca.rb +0 -56
  114. data/lib/puppet/network/client/file.rb +0 -6
  115. data/lib/puppet/network/client/proxy.rb +0 -27
  116. data/lib/puppet/network/client/report.rb +0 -26
  117. data/lib/puppet/network/client/runner.rb +0 -10
  118. data/lib/puppet/network/client/status.rb +0 -4
  119. data/lib/puppet/network/http_server.rb +0 -3
  120. data/lib/puppet/network/http_server/mongrel.rb +0 -130
  121. data/lib/puppet/network/http_server/webrick.rb +0 -155
  122. data/lib/puppet/network/xmlrpc/client.rb +0 -211
  123. data/lib/puppet/provider/file/win32.rb +0 -72
  124. data/lib/puppet/sslcertificates.rb +0 -146
  125. data/lib/puppet/sslcertificates/ca.rb +0 -375
  126. data/lib/puppet/sslcertificates/certificate.rb +0 -255
  127. data/lib/puppet/sslcertificates/inventory.rb +0 -38
  128. data/lib/puppet/sslcertificates/support.rb +0 -146
  129. data/spec/integration/network/client_spec.rb +0 -18
  130. data/spec/unit/network/xmlrpc/client_spec.rb +0 -172
  131. data/spec/unit/sslcertificates/ca_spec.rb +0 -106
  132. data/test/certmgr/certmgr.rb +0 -308
  133. data/test/certmgr/inventory.rb +0 -69
  134. data/test/certmgr/support.rb +0 -105
  135. data/test/network/client/ca.rb +0 -69
  136. data/test/network/client/dipper.rb +0 -34
  137. data/test/network/handler/ca.rb +0 -273
  138. data/test/network/server/mongrel_test.rb +0 -99
  139. data/test/network/server/webrick.rb +0 -111
  140. data/test/network/xmlrpc/client.rb +0 -45
@@ -1,72 +0,0 @@
1
- Puppet::Type.type(:file).provide :microsoft_windows do
2
- desc "Uses Microsoft Windows functionality to manage file's users and rights."
3
-
4
- confine :feature => :microsoft_windows
5
-
6
- include Puppet::Util::Warnings
7
-
8
- require 'sys/admin' if Puppet.features.microsoft_windows?
9
-
10
- def id2name(id)
11
- return id.to_s if id.is_a?(Symbol)
12
- return nil if id > Puppet[:maximum_uid].to_i
13
- # should translate ID numbers to usernames
14
- id
15
- end
16
-
17
- def is_owner_insync?(current, should)
18
- should.each do |value|
19
- if value =~ /^\d+$/
20
- uid = Integer(value)
21
- elsif value.is_a?(String)
22
- fail "Could not find user #{value}" unless uid = uid(value)
23
- else
24
- uid = value
25
- end
26
-
27
- return true if uid == current
28
- end
29
-
30
- unless Puppet.features.root?
31
- warnonce "Cannot manage ownership unless running as root"
32
- return true
33
- end
34
-
35
- false
36
- end
37
-
38
- # Determine if the user is valid, and if so, return the UID
39
- def validuser?(value)
40
- info "Is '#{value}' a valid user?"
41
- return 0
42
- begin
43
- number = Integer(value)
44
- return number
45
- rescue ArgumentError
46
- number = nil
47
- end
48
- (number = uid(value)) && number
49
- end
50
-
51
- def retrieve(resource)
52
- unless stat = resource.stat
53
- return :absent
54
- end
55
-
56
- currentvalue = stat.uid
57
-
58
- # On OS X, files that are owned by -2 get returned as really
59
- # large UIDs instead of negative ones. This isn't a Ruby bug,
60
- # it's an OS X bug, since it shows up in perl, too.
61
- if currentvalue > Puppet[:maximum_uid].to_i
62
- self.warning "Apparently using negative UID (#{currentvalue}) on a platform that does not consistently handle them"
63
- currentvalue = :silly
64
- end
65
-
66
- currentvalue
67
- end
68
-
69
- def sync(path, links, should)
70
- info("should set '%s'%%owner to '%s'" % [path, should])
71
- end
72
- end
@@ -1,146 +0,0 @@
1
- # The library for manipulating SSL certs.
2
-
3
- require 'puppet'
4
-
5
- raise Puppet::Error, "You must have the Ruby openssl library installed" unless Puppet.features.openssl?
6
-
7
- module Puppet::SSLCertificates
8
- #def self.mkcert(type, name, dnsnames, ttl, issuercert, issuername, serial, publickey)
9
- def self.mkcert(hash)
10
- [:type, :name, :ttl, :issuer, :serial, :publickey].each { |param|
11
- raise ArgumentError, "mkcert called without #{param}" unless hash.include?(param)
12
- }
13
-
14
- cert = OpenSSL::X509::Certificate.new
15
- # Make the certificate valid as of yesterday, because
16
- # so many people's clocks are out of sync.
17
- from = Time.now - (60*60*24)
18
-
19
- cert.subject = hash[:name]
20
- if hash[:issuer]
21
- cert.issuer = hash[:issuer].subject
22
- else
23
- # we're a self-signed cert
24
- cert.issuer = hash[:name]
25
- end
26
- cert.not_before = from
27
- cert.not_after = from + hash[:ttl]
28
- cert.version = 2 # X509v3
29
-
30
- cert.public_key = hash[:publickey]
31
- cert.serial = hash[:serial]
32
-
33
- basic_constraint = nil
34
- key_usage = nil
35
- ext_key_usage = nil
36
- subject_alt_name = []
37
-
38
- ef = OpenSSL::X509::ExtensionFactory.new
39
-
40
- ef.subject_certificate = cert
41
-
42
- if hash[:issuer]
43
- ef.issuer_certificate = hash[:issuer]
44
- else
45
- ef.issuer_certificate = cert
46
- end
47
-
48
- ex = []
49
- case hash[:type]
50
- when :ca
51
- basic_constraint = "CA:TRUE"
52
- key_usage = %w{cRLSign keyCertSign}
53
- when :terminalsubca
54
- basic_constraint = "CA:TRUE,pathlen:0"
55
- key_usage = %w{cRLSign keyCertSign}
56
- when :server
57
- basic_constraint = "CA:FALSE"
58
- dnsnames = Puppet[:certdnsnames]
59
- name = hash[:name].to_s.sub(%r{/CN=},'')
60
- if dnsnames != ""
61
- dnsnames.split(':').each { |d| subject_alt_name << 'DNS:' + d }
62
- subject_alt_name << 'DNS:' + name # Add the fqdn as an alias
63
- elsif name == Facter.value(:fqdn) # we're a CA server, and thus probably the server
64
- subject_alt_name << 'DNS:' + "puppet" # Add 'puppet' as an alias
65
- subject_alt_name << 'DNS:' + name # Add the fqdn as an alias
66
- subject_alt_name << 'DNS:' + name.sub(/^[^.]+./, "puppet.") # add puppet.domain as an alias
67
- end
68
- key_usage = %w{digitalSignature keyEncipherment}
69
- ext_key_usage = %w{serverAuth clientAuth emailProtection}
70
- when :ocsp
71
- basic_constraint = "CA:FALSE"
72
- key_usage = %w{nonRepudiation digitalSignature}
73
- ext_key_usage = %w{serverAuth OCSPSigning}
74
- when :client
75
- basic_constraint = "CA:FALSE"
76
- key_usage = %w{nonRepudiation digitalSignature keyEncipherment}
77
- ext_key_usage = %w{clientAuth emailProtection}
78
- ex << ef.create_extension("nsCertType", "client,email")
79
- else
80
- raise Puppet::Error, "unknown cert type '#{hash[:type]}'"
81
- end
82
-
83
-
84
- ex << ef.create_extension(
85
- "nsComment",
86
-
87
- "Puppet Ruby/OpenSSL Generated Certificate")
88
- ex << ef.create_extension("basicConstraints", basic_constraint, true)
89
- ex << ef.create_extension("subjectKeyIdentifier", "hash")
90
-
91
- ex << ef.create_extension("keyUsage", key_usage.join(",")) if key_usage
92
- ex << ef.create_extension("extendedKeyUsage", ext_key_usage.join(",")) if ext_key_usage
93
- ex << ef.create_extension("subjectAltName", subject_alt_name.join(",")) if ! subject_alt_name.empty?
94
-
95
- #if @ca_config[:cdp_location] then
96
- # ex << ef.create_extension("crlDistributionPoints",
97
- # @ca_config[:cdp_location])
98
- #end
99
-
100
- #if @ca_config[:ocsp_location] then
101
- # ex << ef.create_extension("authorityInfoAccess",
102
- # "OCSP;" << @ca_config[:ocsp_location])
103
- #end
104
- cert.extensions = ex
105
-
106
- # for some reason this _must_ be the last extension added
107
- ex << ef.create_extension("authorityKeyIdentifier", "keyid:always,issuer:always") if hash[:type] == :ca
108
-
109
- cert
110
- end
111
-
112
- def self.mkhash(dir, cert, certfile)
113
- # Make sure the hash is zero-padded to 8 chars
114
- hash = "%08x" % cert.issuer.hash
115
- hashpath = nil
116
- 10.times { |i|
117
- path = File.join(dir, "#{hash}.#{i}")
118
- if FileTest.exists?(path)
119
- if FileTest.symlink?(path)
120
- dest = File.readlink(path)
121
- if dest == certfile
122
- # the correct link already exists
123
- hashpath = path
124
- break
125
- else
126
- next
127
- end
128
- else
129
- next
130
- end
131
- end
132
-
133
- File.symlink(certfile, path)
134
-
135
- hashpath = path
136
- break
137
- }
138
-
139
-
140
- hashpath
141
- end
142
- require 'puppet/sslcertificates/certificate'
143
- require 'puppet/sslcertificates/inventory'
144
- require 'puppet/sslcertificates/ca'
145
- end
146
-
@@ -1,375 +0,0 @@
1
- require 'sync'
2
-
3
- class Puppet::SSLCertificates::CA
4
- include Puppet::Util::Warnings
5
-
6
- Certificate = Puppet::SSLCertificates::Certificate
7
- attr_accessor :keyfile, :file, :config, :dir, :cert, :crl
8
-
9
- def certfile
10
- @config[:cacert]
11
- end
12
-
13
- # Remove all traces of a given host. This is kind of hackish, but, eh.
14
- def clean(host)
15
- host = host.downcase
16
- [:csrdir, :signeddir, :publickeydir, :privatekeydir, :certdir].each do |name|
17
- dir = Puppet[name]
18
-
19
- file = File.join(dir, host + ".pem")
20
-
21
- if FileTest.exists?(file)
22
- begin
23
- if Puppet[:name] == "cert"
24
- puts "Removing #{file}"
25
- else
26
- Puppet.info "Removing #{file}"
27
- end
28
- File.unlink(file)
29
- rescue => detail
30
- raise Puppet::Error, "Could not delete #{file}: #{detail}"
31
- end
32
- end
33
-
34
- end
35
- end
36
-
37
- def host2csrfile(hostname)
38
- File.join(Puppet[:csrdir], [hostname.downcase, "pem"].join("."))
39
- end
40
-
41
- # this stores signed certs in a directory unrelated to
42
- # normal client certs
43
- def host2certfile(hostname)
44
- File.join(Puppet[:signeddir], [hostname.downcase, "pem"].join("."))
45
- end
46
-
47
- # Turn our hostname into a Name object
48
- def thing2name(thing)
49
- thing.subject.to_a.find { |ary|
50
- ary[0] == "CN"
51
- }[1]
52
- end
53
-
54
- def initialize(hash = {})
55
- Puppet.settings.use(:main, :ca, :ssl)
56
- self.setconfig(hash)
57
-
58
- if Puppet[:capass]
59
- if FileTest.exists?(Puppet[:capass])
60
- #puts "Reading #{Puppet[:capass]}"
61
- #system "ls -al #{Puppet[:capass]}"
62
- #File.read Puppet[:capass]
63
- @config[:password] = self.getpass
64
- else
65
- # Don't create a password if the cert already exists
66
- @config[:password] = self.genpass unless FileTest.exists?(@config[:cacert])
67
- end
68
- end
69
-
70
- self.getcert
71
- init_crl
72
- unless FileTest.exists?(@config[:serial])
73
- Puppet.settings.write(:serial) do |f|
74
- f << "%04X" % 1
75
- end
76
- end
77
- end
78
-
79
- # Generate a new password for the CA.
80
- def genpass
81
- pass = ""
82
- 20.times { pass += (rand(74) + 48).chr }
83
-
84
- begin
85
- Puppet.settings.write(:capass) { |f| f.print pass }
86
- rescue Errno::EACCES => detail
87
- raise Puppet::Error, detail.to_s
88
- end
89
- pass
90
- end
91
-
92
- # Get the CA password.
93
- def getpass
94
- if @config[:capass] and File.readable?(@config[:capass])
95
- return File.read(@config[:capass])
96
- else
97
- raise Puppet::Error, "Could not decrypt CA key with password: #{detail}"
98
- end
99
- end
100
-
101
- # Get the CA cert.
102
- def getcert
103
- if FileTest.exists?(@config[:cacert])
104
- @cert = OpenSSL::X509::Certificate.new(
105
- File.read(@config[:cacert])
106
- )
107
- else
108
- self.mkrootcert
109
- end
110
- end
111
-
112
- # Retrieve a client's CSR.
113
- def getclientcsr(host)
114
- csrfile = host2csrfile(host)
115
- return nil unless File.exists?(csrfile)
116
-
117
- OpenSSL::X509::Request.new(File.read(csrfile))
118
- end
119
-
120
- # Retrieve a client's certificate.
121
- def getclientcert(host)
122
- certfile = host2certfile(host)
123
- return [nil, nil] unless File.exists?(certfile)
124
-
125
- [OpenSSL::X509::Certificate.new(File.read(certfile)), @cert]
126
- end
127
-
128
- # List certificates waiting to be signed. This returns a list of hostnames, not actual
129
- # files -- the names can be converted to full paths with host2csrfile.
130
- def list(dummy_argument=:work_arround_for_ruby_GC_bug)
131
- return Dir.entries(Puppet[:csrdir]).find_all { |file|
132
- file =~ /\.pem$/
133
- }.collect { |file|
134
- file.sub(/\.pem$/, '')
135
- }
136
- end
137
-
138
- # List signed certificates. This returns a list of hostnames, not actual
139
- # files -- the names can be converted to full paths with host2csrfile.
140
- def list_signed(dummy_argument=:work_arround_for_ruby_GC_bug)
141
- return Dir.entries(Puppet[:signeddir]).find_all { |file|
142
- file =~ /\.pem$/
143
- }.collect { |file|
144
- file.sub(/\.pem$/, '')
145
- }
146
- end
147
-
148
- # Create the root certificate.
149
- def mkrootcert
150
- # Make the root cert's name "Puppet CA: " plus the FQDN of the host running the CA.
151
- name = "Puppet CA: #{Facter["hostname"].value}"
152
- if domain = Facter["domain"].value
153
- name += ".#{domain}"
154
- end
155
-
156
- cert = Certificate.new(
157
- :name => name,
158
- :cert => @config[:cacert],
159
- :encrypt => @config[:capass],
160
- :key => @config[:cakey],
161
- :selfsign => true,
162
- :ttl => ttl,
163
- :type => :ca
164
- )
165
-
166
- # This creates the cakey file
167
- Puppet::Util::SUIDManager.asuser(Puppet[:user], Puppet[:group]) do
168
- @cert = cert.mkselfsigned
169
- end
170
- Puppet.settings.write(:cacert) do |f|
171
- f.puts @cert.to_pem
172
- end
173
- Puppet.settings.write(:capub) do |f|
174
- f.puts @cert.public_key
175
- end
176
- cert
177
- end
178
-
179
- def removeclientcsr(host)
180
- csrfile = host2csrfile(host)
181
- raise Puppet::Error, "No certificate request for #{host}" unless File.exists?(csrfile)
182
-
183
- File.unlink(csrfile)
184
- end
185
-
186
- # Revoke the certificate with serial number SERIAL issued by this
187
- # CA. The REASON must be one of the OpenSSL::OCSP::REVOKED_* reasons
188
- def revoke(serial, reason = OpenSSL::OCSP::REVOKED_STATUS_KEYCOMPROMISE)
189
- time = Time.now
190
- revoked = OpenSSL::X509::Revoked.new
191
- revoked.serial = serial
192
- revoked.time = time
193
- enum = OpenSSL::ASN1::Enumerated(reason)
194
- ext = OpenSSL::X509::Extension.new("CRLReason", enum)
195
- revoked.add_extension(ext)
196
- @crl.add_revoked(revoked)
197
- store_crl
198
- end
199
-
200
- # Take the Puppet config and store it locally.
201
- def setconfig(hash)
202
- @config = {}
203
- Puppet.settings.params("ca").each { |param|
204
- param = param.intern if param.is_a? String
205
- if hash.include?(param)
206
- @config[param] = hash[param]
207
- Puppet[param] = hash[param]
208
- hash.delete(param)
209
- else
210
- @config[param] = Puppet[param]
211
- end
212
- }
213
-
214
- if hash.include?(:password)
215
- @config[:password] = hash[:password]
216
- hash.delete(:password)
217
- end
218
-
219
- raise ArgumentError, "Unknown parameters #{hash.keys.join(",")}" if hash.length > 0
220
-
221
- [:cadir, :csrdir, :signeddir].each { |dir|
222
- raise Puppet::DevError, "#{dir} is undefined" unless @config[dir]
223
- }
224
- end
225
-
226
- # Sign a given certificate request.
227
- def sign(csr)
228
- unless csr.is_a?(OpenSSL::X509::Request)
229
- raise Puppet::Error,
230
- "CA#sign only accepts OpenSSL::X509::Request objects, not #{csr.class}"
231
- end
232
-
233
- raise Puppet::Error, "CSR sign verification failed" unless csr.verify(csr.public_key)
234
-
235
- serial = nil
236
- Puppet.settings.readwritelock(:serial) { |f|
237
- serial = File.read(@config[:serial]).chomp.hex
238
- # increment the serial
239
- f << "%04X" % (serial + 1)
240
- }
241
-
242
- newcert = Puppet::SSLCertificates.mkcert(
243
- :type => :server,
244
- :name => csr.subject,
245
- :ttl => ttl,
246
- :issuer => @cert,
247
- :serial => serial,
248
- :publickey => csr.public_key
249
- )
250
-
251
- sign_with_key(newcert)
252
-
253
- self.storeclientcert(newcert)
254
-
255
- [newcert, @cert]
256
- end
257
-
258
- # Store the client's CSR for later signing. This is called from
259
- # server/ca.rb, and the CSRs are deleted once the certificate is actually
260
- # signed.
261
- def storeclientcsr(csr)
262
- host = thing2name(csr)
263
-
264
- csrfile = host2csrfile(host)
265
- raise Puppet::Error, "Certificate request for #{host} already exists" if File.exists?(csrfile)
266
-
267
- Puppet.settings.writesub(:csrdir, csrfile) do |f|
268
- f.print csr.to_pem
269
- end
270
- end
271
-
272
- # Store the certificate that we generate.
273
- def storeclientcert(cert)
274
- host = thing2name(cert)
275
-
276
- certfile = host2certfile(host)
277
- Puppet.notice "Overwriting signed certificate #{certfile} for #{host}" if File.exists?(certfile)
278
-
279
- Puppet::SSLCertificates::Inventory::add(cert)
280
- Puppet.settings.writesub(:signeddir, certfile) do |f|
281
- f.print cert.to_pem
282
- end
283
- end
284
-
285
- # TTL for new certificates in seconds. If config param :ca_ttl is set,
286
- # use that, otherwise use :ca_days for backwards compatibility
287
- def ttl
288
- days = @config[:ca_days]
289
- if days && days.size > 0
290
- warnonce "Parameter ca_ttl is not set. Using depecated ca_days instead."
291
- return @config[:ca_days] * 24 * 60 * 60
292
- else
293
- ttl = @config[:ca_ttl]
294
- if ttl.is_a?(String)
295
- unless ttl =~ /^(\d+)(y|d|h|s)$/
296
- raise ArgumentError, "Invalid ca_ttl #{ttl}"
297
- end
298
- case $2
299
- when 'y'
300
- unit = 365 * 24 * 60 * 60
301
- when 'd'
302
- unit = 24 * 60 * 60
303
- when 'h'
304
- unit = 60 * 60
305
- when 's'
306
- unit = 1
307
- else
308
- raise ArgumentError, "Invalid unit for ca_ttl #{ttl}"
309
- end
310
- return $1.to_i * unit
311
- else
312
- return ttl
313
- end
314
- end
315
- end
316
-
317
- private
318
- def init_crl
319
- if FileTest.exists?(@config[:cacrl])
320
- @crl = OpenSSL::X509::CRL.new(
321
- File.read(@config[:cacrl])
322
- )
323
- else
324
- # Create new CRL
325
- @crl = OpenSSL::X509::CRL.new
326
- @crl.issuer = @cert.subject
327
- @crl.version = 1
328
- store_crl
329
- @crl
330
- end
331
- end
332
-
333
- def store_crl
334
- # Increment the crlNumber
335
- e = @crl.extensions.find { |e| e.oid == 'crlNumber' }
336
- ext = @crl.extensions.reject { |e| e.oid == 'crlNumber' }
337
- crlNum = OpenSSL::ASN1::Integer(e ? e.value.to_i + 1 : 0)
338
- ext << OpenSSL::X509::Extension.new("crlNumber", crlNum)
339
- @crl.extensions = ext
340
-
341
- # Set last/next update
342
- now = Time.now
343
- @crl.last_update = now
344
- # Keep CRL valid for 5 years
345
- @crl.next_update = now + 5 * 365*24*60*60
346
-
347
- sign_with_key(@crl)
348
- Puppet.settings.write(:cacrl) do |f|
349
- f.puts @crl.to_pem
350
- end
351
- end
352
-
353
- def sign_with_key(signable, digest = OpenSSL::Digest::SHA1.new)
354
- cakey = nil
355
- if @config[:password]
356
- begin
357
- cakey = OpenSSL::PKey::RSA.new(
358
- File.read(@config[:cakey]), @config[:password]
359
- )
360
- rescue
361
- raise Puppet::Error,
362
- "Decrypt of CA private key with password stored in @config[:capass] not possible"
363
- end
364
- else
365
- cakey = OpenSSL::PKey::RSA.new(
366
- File.read(@config[:cakey])
367
- )
368
- end
369
-
370
- raise Puppet::Error, "CA Certificate is invalid" unless @cert.check_private_key(cakey)
371
-
372
- signable.sign(cakey, digest)
373
- end
374
- end
375
-