diff options
| author | luke <luke@980ebf18-57e1-0310-9a29-db15c13687c0> | 2006-12-27 17:18:35 +0000 |
|---|---|---|
| committer | luke <luke@980ebf18-57e1-0310-9a29-db15c13687c0> | 2006-12-27 17:18:35 +0000 |
| commit | 8ff7e0c75eda0291a169074c67fa0a90db9c4e7b (patch) | |
| tree | 412ef1e461736028c982176dbec377e5016a80c5 | |
| parent | f1dc103396511d30aa8ae42036b6aa1aee712da3 (diff) | |
| download | puppet-8ff7e0c75eda0291a169074c67fa0a90db9c4e7b.tar.gz puppet-8ff7e0c75eda0291a169074c67fa0a90db9c4e7b.tar.xz puppet-8ff7e0c75eda0291a169074c67fa0a90db9c4e7b.zip | |
Closing #362. Case-insensitivity is handled by downcasing all host names.
git-svn-id: https://reductivelabs.com/svn/puppet/trunk@1971 980ebf18-57e1-0310-9a29-db15c13687c0
| -rwxr-xr-x | bin/puppetca | 23 | ||||
| -rw-r--r-- | lib/puppet/sslcertificates/ca.rb | 106 | ||||
| -rwxr-xr-x | test/certmgr/ca.rb | 72 | ||||
| -rwxr-xr-x | test/certmgr/certmgr.rb | 9 | ||||
| -rwxr-xr-x | test/executables/puppetca.rb | 92 |
5 files changed, 185 insertions, 117 deletions
diff --git a/bin/puppetca b/bin/puppetca index 599ce58b4..92290c694 100755 --- a/bin/puppetca +++ b/bin/puppetca @@ -167,11 +167,11 @@ unless mode exit(12) end -if mode == :generate or mode == :clean or mode == :revoke - hosts = ARGV +if [:generate, :clean, :revoke].include?(mode) + hosts = ARGV.collect { |h| h.downcase } else - hosts = ca.list - unless hosts.length > 0 + waiting = ca.list + unless waiting.length > 0 puts "No certificates to sign" if ARGV.length > 0 exit(17) @@ -179,11 +179,12 @@ else exit(0) end end + to_sign = ARGV.collect { |h| h.downcase } end case mode when :list - puts hosts.join("\n") + puts waiting.join("\n") when :clean if hosts.empty? $stderr.puts "You must specify one or more hosts to clean" @@ -193,7 +194,7 @@ when :clean ca.clean(host) end when :sign - unless ARGV.length > 0 or all + unless to_sign.length > 0 or all $stderr.puts( "You must specify to sign all certificates or you must specify hostnames" ) @@ -201,17 +202,17 @@ when :sign end unless all - ARGV.each { |host| - unless hosts.include?(host) + to_sign.each { |host| + unless waiting.include?(host) $stderr.puts "No waiting request for %s" % host end } - hosts = hosts.find_all { |host| - ARGV.include?(host) + waiting = waiting.find_all { |host| + to_sign.include?(host) } end - hosts.each { |host| + waiting.each { |host| begin csr = ca.getclientcsr(host) rescue => detail diff --git a/lib/puppet/sslcertificates/ca.rb b/lib/puppet/sslcertificates/ca.rb index 19ea27228..572abafd7 100644 --- a/lib/puppet/sslcertificates/ca.rb +++ b/lib/puppet/sslcertificates/ca.rb @@ -85,40 +85,9 @@ class Puppet::SSLCertificates::CA @config[:cacert] end - # TTL for new certificates in seconds. If config param :ca_ttl is set, - # use that, otherwise use :ca_days for backwards compatibility - def ttl - days = @config[:ca_days] - if days && days.size > 0 - warnonce "Parameter ca_ttl is not set. Using depecated ca_days instead." - return @config[:ca_days] * 24 * 60 * 60 - else - ttl = @config[:ca_ttl] - if ttl.is_a?(String) - unless ttl =~ /^(\d+)(y|d|h|s)$/ - raise ArgumentError, "Invalid ca_ttl #{ttl}" - end - case $2 - when 'y' - unit = 365 * 24 * 60 * 60 - when 'd' - unit = 24 * 60 * 60 - when 'h' - unit = 60 * 60 - when 's' - unit = 1 - else - raise ArgumentError, "Invalid unit for ca_ttl #{ttl}" - end - return $1.to_i * unit - else - return ttl - end - end - end - # Remove all traces of a given host. This is kind of hackish, but, eh. def clean(host) + host = host.downcase [:csrdir, :signeddir, :publickeydir, :privatekeydir, :certdir].each do |name| dir = Puppet[name] @@ -142,13 +111,13 @@ class Puppet::SSLCertificates::CA end def host2csrfile(hostname) - File.join(Puppet[:csrdir], [hostname, "pem"].join(".")) + File.join(Puppet[:csrdir], [hostname.downcase, "pem"].join(".")) end # this stores signed certs in a directory unrelated to # normal client certs def host2certfile(hostname) - File.join(Puppet[:signeddir], [hostname, "pem"].join(".")) + File.join(Puppet[:signeddir], [hostname.downcase, "pem"].join(".")) end # Turn our hostname into a Name object @@ -238,7 +207,8 @@ class Puppet::SSLCertificates::CA return [OpenSSL::X509::Certificate.new(File.read(certfile)), @cert] end - # List certificates waiting to be signed. + # List certificates waiting to be signed. This returns a list of hostnames, not actual + # files -- the names can be converted to full paths with host2csrfile. def list return Dir.entries(Puppet[:csrdir]).find_all { |file| file =~ /\.pem$/ @@ -283,6 +253,23 @@ class Puppet::SSLCertificates::CA File.unlink(csrfile) end + # Revoke the certificate with serial number SERIAL issued by this + # CA. The REASON must be one of the OpenSSL::OCSP::REVOKED_* reasons + def revoke(serial, reason = OpenSSL::OCSP::REVOKED_STATUS_KEYCOMPROMISE) + if @config[:cacrl] == 'none' + raise Puppet::Error, "Revocation requires a CRL, but ca_crl is set to 'none'" + end + time = Time.now + revoked = OpenSSL::X509::Revoked.new + revoked.serial = serial + revoked.time = time + enum = OpenSSL::ASN1::Enumerated(reason) + ext = OpenSSL::X509::Extension.new("CRLReason", enum) + revoked.add_extension(ext) + @crl.add_revoked(revoked) + store_crl + end + # Take the Puppet config and store it locally. def setconfig(hash) @config = {} @@ -363,23 +350,6 @@ class Puppet::SSLCertificates::CA end end - # Revoke the certificate with serial number SERIAL issued by this - # CA. The REASON must be one of the OpenSSL::OCSP::REVOKED_* reasons - def revoke(serial, reason = OpenSSL::OCSP::REVOKED_STATUS_KEYCOMPROMISE) - if @config[:cacrl] == 'none' - raise Puppet::Error, "Revocation requires a CRL, but ca_crl is set to 'none'" - end - time = Time.now - revoked = OpenSSL::X509::Revoked.new - revoked.serial = serial - revoked.time = time - enum = OpenSSL::ASN1::Enumerated(reason) - ext = OpenSSL::X509::Extension.new("CRLReason", enum) - revoked.add_extension(ext) - @crl.add_revoked(revoked) - store_crl - end - # Store the certificate that we generate. def storeclientcert(cert) host = thing2name(cert) @@ -396,6 +366,38 @@ class Puppet::SSLCertificates::CA end end + # TTL for new certificates in seconds. If config param :ca_ttl is set, + # use that, otherwise use :ca_days for backwards compatibility + def ttl + days = @config[:ca_days] + if days && days.size > 0 + warnonce "Parameter ca_ttl is not set. Using depecated ca_days instead." + return @config[:ca_days] * 24 * 60 * 60 + else + ttl = @config[:ca_ttl] + if ttl.is_a?(String) + unless ttl =~ /^(\d+)(y|d|h|s)$/ + raise ArgumentError, "Invalid ca_ttl #{ttl}" + end + case $2 + when 'y' + unit = 365 * 24 * 60 * 60 + when 'd' + unit = 24 * 60 * 60 + when 'h' + unit = 60 * 60 + when 's' + unit = 1 + else + raise ArgumentError, "Invalid unit for ca_ttl #{ttl}" + end + return $1.to_i * unit + else + return ttl + end + end + end + private def init_crl if FileTest.exists?(@config[:cacrl]) diff --git a/test/certmgr/ca.rb b/test/certmgr/ca.rb new file mode 100755 index 000000000..d01725970 --- /dev/null +++ b/test/certmgr/ca.rb @@ -0,0 +1,72 @@ +#!/usr/bin/env ruby + +$:.unshift("../lib").unshift("../../lib") if __FILE__ =~ /\.rb$/ + +require 'puppet' +require 'puppet/sslcertificates/ca.rb' +require 'puppettest' +require 'puppettest/certificates' + +class TestCA < Test::Unit::TestCase + include PuppetTest + def hosts + %w{host.domain.com Other.Testing.Com} + end + def mkca + Puppet::SSLCertificates::CA.new + end + + def test_clean + dirs = [:csrdir, :signeddir, :publickeydir, :privatekeydir, :certdir] + ca = mkca + + hosts.each do |host| + files = [] + dirs.each do |dir| + dir = Puppet[dir] + # We handle case insensitivity through downcasing + file = File.join(dir, host.downcase + ".pem") + File.open(file, "w") do |f| + f.puts "testing" + end + files << file + end + assert_nothing_raised do + ca.clean(host) + end + files.each do |f| + assert(! FileTest.exists?(f), "File %s was not deleted" % f) + end + end + end + + def test_host2Xfile + ca = mkca + hosts.each do |host| + {:signeddir => :host2certfile, :csrdir => :host2csrfile}.each do |dir, method| + val = nil + assert_nothing_raised do + val = ca.send(method, host) + end + assert_equal(File.join(Puppet[dir], host.downcase + ".pem"), val, + "incorrect response from %s" % method) + end + end + end + + def test_list + ca = mkca + # Make a fake csr + dir = Puppet[:csrdir] + list = [] + hosts.each do |host| + file = File.join(dir, host.downcase + ".pem") + File.open(file, "w") { |f| f.puts "yay" } + list << host.downcase + end + + assert_equal(list.sort, ca.list.sort, "list was not correct") + end +end + +# $Id$ diff --git a/test/certmgr/certmgr.rb b/test/certmgr/certmgr.rb index 32934e8ce..90d516cb4 100755 --- a/test/certmgr/certmgr.rb +++ b/test/certmgr/certmgr.rb @@ -7,15 +7,6 @@ require 'puppet/sslcertificates.rb' require 'puppettest' require 'puppettest/certificates' -# so, what kind of things do we want to test? - -# we don't need to test function, since we're confident in the -# library tests. We do, however, need to test how things are actually -# working in the language. - -# so really, we want to do things like test that our ast is correct -# and test whether we've got things in the right scopes - class TestCertMgr < Test::Unit::TestCase include PuppetTest::Certificates def setup diff --git a/test/executables/puppetca.rb b/test/executables/puppetca.rb index f96e7a5f5..2eafb7f6c 100755 --- a/test/executables/puppetca.rb +++ b/test/executables/puppetca.rb @@ -9,6 +9,16 @@ require 'puppettest' class TestPuppetCA < Test::Unit::TestCase include PuppetTest::ExeTest + + def gen_cert(ca, host) + runca("-g #{host}") + ca.getclientcert(host)[0] + end + + def mkca + Puppet::Server::CA.new() + end + def mkcert(hostname) cert = nil assert_nothing_raised { @@ -27,59 +37,53 @@ class TestPuppetCA < Test::Unit::TestCase debug = "-d " end return %x{puppetca --user=#{Puppet[:user]} #{debug} --group=#{Puppet[:group]} --confdir=#{Puppet[:confdir]} --vardir=#{Puppet[:vardir]} #{args} 2>&1} - end def test_signing - ca = nil + ca = mkca Puppet[:autosign] = false - assert_nothing_raised { - ca = Puppet::Server::CA.new() - } - #Puppet.warning "SSLDir is %s" % Puppet[:confdir] - #system("find %s" % Puppet[:confdir]) + + %w{host.test.com Other.Testing.Com}.each do |host| + cert = mkcert(host) + resp = nil + assert_nothing_raised { + # We need to use a fake name so it doesn't think the cert is from + # itself. Strangely, getcert stores the csr, because it's a server-side + # method, not client. + resp = ca.getcert(cert.csr.to_pem, host, "127.0.0.1") + } + assert_equal(["",""], resp) - cert = mkcert("host.test.com") - resp = nil - assert_nothing_raised { - # We need to use a fake name so it doesn't think the cert is from - # itself. - resp = ca.getcert(cert.csr.to_pem, "fakename", "127.0.0.1") - } - assert_equal(["",""], resp) - #Puppet.warning "SSLDir is %s" % Puppet[:confdir] - #system("find %s" % Puppet[:confdir]) - - output = nil - assert_nothing_raised { - output = runca("--list").chomp.split("\n").reject { |line| line =~ /warning:/ } # stupid ssl.rb - } - #Puppet.warning "SSLDir is %s" % Puppet[:confdir] - #system("find %s" % Puppet[:confdir]) - assert_equal($?,0) - assert_equal(%w{host.test.com}, output) - assert_nothing_raised { - output = runca("--sign -a").chomp.split("\n") - } + output = nil + assert_nothing_raised { + output = runca("--list").chomp.split("\n").reject { |line| line =~ /warning:/ } # stupid ssl.rb + } + assert_equal($?,0) + assert_equal([host.downcase], output) + assert_nothing_raised { + output = runca("--sign -a").chomp.split("\n") + } - assert_equal($?,0) - assert_equal(["Signed host.test.com"], output) + assert_equal($?,0) + assert_equal(["Signed #{host.downcase}"], output) - signedfile = File.join(Puppet[:signeddir], "host.test.com.pem") - assert(FileTest.exists?(signedfile), "cert does not exist") - assert(! FileTest.executable?(signedfile), "cert is executable") + + signedfile = ca.ca.host2certfile(host) + assert(FileTest.exists?(signedfile), "cert does not exist") + assert(! FileTest.executable?(signedfile), "cert is executable") - uid = Puppet::Util.uid(Puppet[:user]) + uid = Puppet::Util.uid(Puppet[:user]) - if Puppet::SUIDManager.uid == 0 - assert(! FileTest.owned?(signedfile), "cert is owned by root") + if Puppet::SUIDManager.uid == 0 + assert(! FileTest.owned?(signedfile), "cert is owned by root") + end + assert_nothing_raised { + output = runca("--list").chomp.split("\n") + } + assert_equal($?,0) + assert_equal(["No certificates to sign"], output) end - assert_nothing_raised { - output = runca("--list").chomp.split("\n") - } - assert_equal($?,0) - assert_equal(["No certificates to sign"], output) end # This method takes a long time to run because of all of the external @@ -102,9 +106,7 @@ class TestPuppetCA < Test::Unit::TestCase assert_equal(exp, revoked) end - def gen_cert(ca, host) - runca("-g #{host}") - ca.getclientcert(host)[0] + def test_case_insensitive_sign end end |
