diff options
-rw-r--r-- | lib/puppet/ssl/certificate_authority.rb | 91 | ||||
-rw-r--r-- | spec/integration/network/server/mongrel.rb | 2 | ||||
-rwxr-xr-x | spec/unit/ssl/certificate_authority.rb | 147 |
3 files changed, 84 insertions, 156 deletions
diff --git a/lib/puppet/ssl/certificate_authority.rb b/lib/puppet/ssl/certificate_authority.rb index 3192c2844..f4bc6fe31 100644 --- a/lib/puppet/ssl/certificate_authority.rb +++ b/lib/puppet/ssl/certificate_authority.rb @@ -1,65 +1,40 @@ require 'puppet/ssl/host' - -# The class that knows how to sign certificates. It's just a -# special case of the SSL::Host -- it's got a sign method, -# and it reads its info from a different location. -class Puppet::SSL::CertificateAuthority < Puppet::SSL::Host +require 'puppet/ssl/certificate_request' + +# The class that knows how to sign certificates. It creates +# a 'special' SSL::Host whose name is 'ca', thus indicating +# that, well, it's the CA. There's some magic in the +# indirector/ssl_file terminus base class that does that +# for us. +# This class mostly just signs certs for us, but +# it can also be seen as a general interface into all of the +# SSL stuff. +class Puppet::SSL::CertificateAuthority require 'puppet/ssl/certificate_factory' - # Provide the path to our password, and read our special ca key. - def read_key - return nil unless FileTest.exist?(Puppet[:cakey]) - - key = Puppet::SSL::Key.new(name) - key.password_file = Puppet[:capass] - key.read(Puppet[:cakey]) - - return key - end - - # Generate and write the key out. - def generate_key - @key = Key.new(name) - @key.password_file = Puppet[:capass] - @key.generate - Puppet.settings.write(:cakey) do |f| - f.print @key.to_s - end - true - end - - # Read the special path to our key. - def read_certificate - return nil unless FileTest.exist?(Puppet[:cacert]) - cert = Puppet::SSL::Certificate.new(name) - cert.read(Puppet[:cacert]) + attr_reader :name, :host - return cert - end + # Generate our CA certificate. + def generate_ca_certificate + generate_password unless password? - # The CA creates a self-signed certificate, rather than relying - # on someone else to do the work. - def generate_certificate - request = CertificateRequest.new(name) - request.generate(key) + # Create a new cert request. We do this + # specially, because we don't want to actually + # save the request anywhere. + request = Puppet::SSL::CertificateRequest.new(host.name) + request.generate(host.key) # Create a self-signed certificate. @certificate = sign(name, :ca, request) - - Puppet.settings.write(:cacert) do |f| - f.print @certificate.to_s - end - - return true end def initialize Puppet.settings.use :main, :ssl, :ca - # Always name the ca after the host we're running on. - super(Puppet[:certname]) + @name = Puppet[:certname] - setup_ca() + @host = Puppet::SSL::Host.new(Puppet::SSL::Host.ca_name) + @host.password_file = Puppet[:capass] end # Sign a given certificate request. @@ -83,27 +58,13 @@ class Puppet::SSL::CertificateAuthority < Puppet::SSL::Host Puppet.notice "Signed certificate request for %s" % host - # Save the now-signed cert, unless it's a self-signed cert, since we - # assume it goes somewhere else. - cert.save(:in => :ca_file) unless self_signing_csr + # Save the now-signed cert. This should get routed correctly depending + # on the certificate type. + cert.save return cert end - # Do all of the initialization necessary to set up our - # ca. - def setup_ca - # Make sure we've got a password protecting our private key. - generate_password unless password? - - generate_key unless key - - # And then make sure we've got the whole kaboodle. This will - # create a self-signed CA certificate if we don't already have one, - # and it will just read it in if we do. - generate_certificate unless certificate - end - # Generate a new password for the CA. def generate_password pass = "" diff --git a/spec/integration/network/server/mongrel.rb b/spec/integration/network/server/mongrel.rb index 65caf78c9..a4089585e 100644 --- a/spec/integration/network/server/mongrel.rb +++ b/spec/integration/network/server/mongrel.rb @@ -43,4 +43,4 @@ describe Puppet::Network::Server do @server.unlisten if @server.listening? end end -end
\ No newline at end of file +end diff --git a/spec/unit/ssl/certificate_authority.rb b/spec/unit/ssl/certificate_authority.rb index e9624f218..37832ecf2 100755 --- a/spec/unit/ssl/certificate_authority.rb +++ b/spec/unit/ssl/certificate_authority.rb @@ -6,126 +6,91 @@ require 'puppet/ssl/certificate_authority' describe Puppet::SSL::CertificateAuthority do describe "when initializing" do - it "should always set its name to the value of :certname" do + before do Puppet.settings.stubs(:use) - Puppet.settings.expects(:value).with(:certname).returns "whatever" - - Puppet::SSL::CertificateAuthority.any_instance.stubs(:setup_ca) - - Puppet::SSL::CertificateAuthority.new.name.should == "whatever" - end + Puppet.settings.stubs(:value).returns "whatever" - it "should use the :main, :ca, and :ssl settings sections" do - Puppet.settings.expects(:use).with(:main, :ssl, :ca) - Puppet::SSL::CertificateAuthority.any_instance.stubs(:setup_ca) - Puppet::SSL::CertificateAuthority.new + Puppet::SSL::CertificateAuthority.any_instance.stubs(:generate_ca_certificate) end - describe "a new certificate authority" do - before do - Puppet.settings.stubs(:use) - Puppet.settings.stubs(:value).with(:certname).returns "whatever" - end + it "should always set its name to the value of :certname" do + Puppet.settings.expects(:value).with(:certname).returns "whatever" - it "should create and store a password at :capass" do - Puppet.settings.expects(:value).with(:capass).returns "/path/to/pass" + Puppet::SSL::CertificateAuthority.new.name.should == "whatever" + end - FileTest.expects(:exist?).with("/path/to/pass").returns false + it "should create an SSL::Host instance whose name is the 'ca_name'" do + Puppet::SSL::Host.expects(:ca_name).returns "caname" - fh = mock 'filehandle' - Puppet.settings.expects(:write).with(:capass).yields fh + host = stub 'host', :password_file= => nil + Puppet::SSL::Host.expects(:new).with("caname").returns host - fh.expects(:print).with { |s| s.length > 18 } + Puppet::SSL::CertificateAuthority.new + end - [:read_key, :generate_key, :read_certificate, :generate_certificate].each do |method| - Puppet::SSL::CertificateAuthority.any_instance.stubs(method) - end + it "should set the Host instance's password file to the :capass setting" do + Puppet.settings.stubs(:value).with(:capass).returns "/ca/pass" - Puppet::SSL::CertificateAuthority.new - end + host = mock 'host' + Puppet::SSL::Host.expects(:new).returns host - it "should create and store a key encrypted with the password at :cakey" do - Puppet.settings.stubs(:value).with(:capass).returns "/path/to/pass" - Puppet.settings.stubs(:value).with(:cakey).returns "/path/to/key" + host.expects(:password_file=).with "/ca/pass" - FileTest.expects(:exist?).with("/path/to/key").returns false + Puppet::SSL::CertificateAuthority.new + end - key = mock 'key' + it "should use the :main, :ca, and :ssl settings sections" do + Puppet.settings.expects(:use).with(:main, :ssl, :ca) + Puppet::SSL::CertificateAuthority.new + end + end - Puppet::SSL::Key.expects(:new).with("whatever").returns key - key.expects(:password_file=).with("/path/to/pass") - key.expects(:generate) + it "should generate a self-signed certificate if its Host instance has no certificate" - key.expects(:to_s).returns "my key" + describe "when generating a self-signed CA certificate" do + before do + Puppet.settings.stubs(:use) + Puppet.settings.stubs(:value).returns "whatever" - fh = mock 'filehandle' - Puppet.settings.expects(:write).with(:cakey).yields fh - fh.expects(:print).with("my key") + @ca = Puppet::SSL::CertificateAuthority.new - [:generate_password, :read_certificate, :generate_certificate].each do |method| - Puppet::SSL::CertificateAuthority.any_instance.stubs(method) - end - Puppet::SSL::CertificateAuthority.any_instance.stubs(:password?).returns true + @host = stub 'host', :key => mock("key"), :name => "hostname" - Puppet::SSL::CertificateAuthority.new - end + Puppet::SSL::CertificateRequest.any_instance.stubs(:generate) - it "should create, sign, and store a self-signed cert at :cacert" do - Puppet.settings.stubs(:value).with(:cacert).returns "/path/to/cert" + @ca.stubs(:host).returns @host + end - FileTest.expects(:exist?).with("/path/to/cert").returns false + it "should create and store a password at :capass" do + Puppet.settings.expects(:value).with(:capass).returns "/path/to/pass" - request = mock 'request' - Puppet::SSL::CertificateRequest.expects(:new).with("whatever").returns request - request.expects(:generate) + FileTest.expects(:exist?).with("/path/to/pass").returns false - cert = mock 'cert' - cert.expects(:to_s).returns "my cert" - Puppet::SSL::CertificateAuthority.any_instance.expects(:sign).with("whatever", :ca, request).returns cert + fh = mock 'filehandle' + Puppet.settings.expects(:write).with(:capass).yields fh - fh = mock 'filehandle' - Puppet.settings.expects(:write).with(:cacert).yields fh - fh.expects(:print).with("my cert") + fh.expects(:print).with { |s| s.length > 18 } - [:password?, :generate_password, :read_key, :generate_key].each do |method| - Puppet::SSL::CertificateAuthority.any_instance.stubs(method) - end + @ca.stubs(:sign) - Puppet::SSL::CertificateAuthority.new - end + @ca.generate_ca_certificate end - describe "an existing certificate authority" do - it "should read and decrypt the key at :cakey using the password at :capass and it should read the cert at :cacert" do - Puppet.settings.stubs(:value).with(:certname).returns "whatever" - Puppet.settings.stubs(:use) + it "should create and sign a self-signed cert" do + request = mock 'request' + Puppet::SSL::CertificateRequest.expects(:new).with(@ca.host.name).returns request + request.expects(:generate).with(@ca.host.key) - paths = {} - [:capass, :cakey, :cacert].each do |value| - paths[value] = "/path/to/#{value.to_s}" - Puppet.settings.stubs(:value).with(value).returns paths[value] - FileTest.stubs(:exist?).with(paths[value]).returns true - end + @ca.expects(:sign).with(@ca.name, :ca, request) - key = mock 'key' - Puppet::SSL::Key.expects(:new).with("whatever").returns key - key.expects(:password_file=).returns paths[:capass] - key.expects(:read).returns paths[:cakey] - key.stubs(:content).returns "mykey" + @ca.stubs :generate_password - cert = mock 'cert' - Puppet::SSL::Certificate.expects(:new).with("whatever").returns cert - cert.expects(:read).returns paths[:cacert] - cert.stubs(:content).returns "mycert" - - Puppet::SSL::CertificateAuthority.new - end + @ca.generate_ca_certificate end end describe "when signing" do before do - Puppet.settings.stubs(:value).with(:certname).returns "whatever" Puppet.settings.stubs(:use) Puppet::SSL::CertificateAuthority.any_instance.stubs(:password?).returns true @@ -146,6 +111,7 @@ describe Puppet::SSL::CertificateAuthority do Puppet::SSL::Certificate.stubs(:new).returns @cert @cert.stubs(:content=) + @cert.stubs(:save) @factory = stub 'factory', :result => "my real cert" Puppet::SSL::CertificateFactory.stubs(:new).returns @factory @@ -226,8 +192,10 @@ describe Puppet::SSL::CertificateAuthority do @ca.sign(@name, :ca, @request) end - it "should not save the resulting certificate" do - @cert.expects(:save).never + it "should save the resulting certificate" do + @cert.expects(:save) + + @ca.sign(@name, :ca, @request) end end @@ -293,8 +261,8 @@ describe Puppet::SSL::CertificateAuthority do @ca.sign(@name) end - it "should save the resulting certificate in the :ca_file terminus" do - @cert.expects(:save).with(:in => :ca_file) + it "should save the resulting certificate" do + @cert.expects(:save) @ca.sign(@name) end end @@ -322,7 +290,6 @@ describe Puppet::SSL::CertificateAuthority do describe "when managing certificate clients" do before do - Puppet.settings.stubs(:value).with(:certname).returns "whatever" Puppet.settings.stubs(:use) Puppet::SSL::CertificateAuthority.any_instance.stubs(:password?).returns true |