summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLuke Kanies <luke@madstop.com>2008-03-11 14:19:11 -0700
committerLuke Kanies <luke@madstop.com>2008-04-15 21:34:04 -0500
commit8347b0605612128b1a9e9f2d2d2e5ea73dae288d (patch)
treea21919fc0fb1bbe5986c4801247512988418b93b
parent50f3c18c4e1d54790983262b5e285c529358fb43 (diff)
downloadpuppet-8347b0605612128b1a9e9f2d2d2e5ea73dae288d.tar.gz
puppet-8347b0605612128b1a9e9f2d2d2e5ea73dae288d.tar.xz
puppet-8347b0605612128b1a9e9f2d2d2e5ea73dae288d.zip
The certificate and key are now correctly interacting
with the existing cert/key store. Certificate requests are not yet handled, nor are the ca-specific collections.
-rw-r--r--lib/puppet/indirector/key/file.rb48
-rw-r--r--lib/puppet/indirector/ssl_file.rb5
-rw-r--r--lib/puppet/ssl.rb3
-rwxr-xr-xspec/unit/indirector/certificate/file.rb90
-rwxr-xr-xspec/unit/indirector/key/file.rb167
-rwxr-xr-xspec/unit/indirector/ssl_file.rb130
6 files changed, 201 insertions, 242 deletions
diff --git a/lib/puppet/indirector/key/file.rb b/lib/puppet/indirector/key/file.rb
index d4f39ac2e..9efcd1a31 100644
--- a/lib/puppet/indirector/key/file.rb
+++ b/lib/puppet/indirector/key/file.rb
@@ -1,40 +1,36 @@
-require 'puppet/indirector/file'
+require 'puppet/indirector/ssl_file'
require 'puppet/ssl/key'
-class Puppet::SSL::Key::File < Puppet::Indirector::File
+class Puppet::SSL::Key::File < Puppet::Indirector::SslFile
desc "Manage SSL private and public keys on disk."
- def path(name)
- if name == :ca
- Puppet.settings[:cakey]
- else
- File.join(Puppet.settings[:privatekeydir], name.to_s + ".pem")
- end
- end
+ store_in :privatekeydir
def public_key_path(name)
- if name == :ca
- Puppet.settings[:capub]
- else
- File.join(Puppet.settings[:publickeydir], name.to_s + ".pem")
- end
+ File.join(Puppet[:publickeydir], name.to_s + ".pem")
end
- def save(key)
- # Save the private key
- File.open(path(key.name), "w") { |f| f.print key.to_pem }
+ # Remove the public key, in addition to the private key
+ def destroy(key)
+ super
- # Now save the public key
- File.open(public_key_path(name), "w") { |f| f.print key.to_pem }
- end
+ return unless FileTest.exist?(public_key_path(key.name))
- def find(name)
- return nil unless FileTest.exist?(path(name))
- OpenSSL::PKey::RSA.new(File.read(path(name)))
+ begin
+ File.unlink(public_key_path(key.name))
+ rescue => detail
+ raise Puppet::Error, "Could not remove %s public key: %s" % [key.name, detail]
+ end
end
- def destroy(name)
- return nil unless FileTest.exist?(path(name))
- File.unlink(path(name)) and true
+ # Save the public key, in addition to the private key.
+ def save(key)
+ super
+
+ begin
+ File.open(public_key_path(key.name), "w") { |f| f.print key.content.public_key.to_pem }
+ rescue => detail
+ raise Puppet::Error, "Could not write %s: %s" % [key, detail]
+ end
end
end
diff --git a/lib/puppet/indirector/ssl_file.rb b/lib/puppet/indirector/ssl_file.rb
index 50e9eb8df..6125d46e4 100644
--- a/lib/puppet/indirector/ssl_file.rb
+++ b/lib/puppet/indirector/ssl_file.rb
@@ -9,6 +9,7 @@ class Puppet::Indirector::SslFile < Puppet::Indirector::Terminus
attr_reader :directory_setting
end
+ # The full path to where we should store our files.
def self.collection_directory
raise(Puppet::DevError, "No setting defined for %s" % self) unless @directory_setting
Puppet.settings[@directory_setting]
@@ -23,6 +24,7 @@ class Puppet::Indirector::SslFile < Puppet::Indirector::Terminus
File.join(collection_directory, name.to_s + ".pem")
end
+ # Remove our file.
def destroy(file)
path = path(file.name)
raise Puppet::Error.new("File %s does not exist; cannot destroy" % [file]) unless FileTest.exist?(path)
@@ -34,6 +36,7 @@ class Puppet::Indirector::SslFile < Puppet::Indirector::Terminus
end
end
+ # Find the file on disk, returning an instance of the model.
def find(name)
path = path(name)
@@ -44,6 +47,7 @@ class Puppet::Indirector::SslFile < Puppet::Indirector::Terminus
result
end
+ # Save our file to disk.
def save(file)
path = path(file.name)
dir = File.dirname(path)
@@ -60,6 +64,7 @@ class Puppet::Indirector::SslFile < Puppet::Indirector::Terminus
private
+ # A demeterish pointer to the collection directory.
def collection_directory
self.class.collection_directory
end
diff --git a/lib/puppet/ssl.rb b/lib/puppet/ssl.rb
index ae8f0abea..68c65ca80 100644
--- a/lib/puppet/ssl.rb
+++ b/lib/puppet/ssl.rb
@@ -1,3 +1,6 @@
# Just to make the constants work out.
+require 'puppet'
+require 'openssl'
+
module Puppet::SSL # :nodoc:
end
diff --git a/spec/unit/indirector/certificate/file.rb b/spec/unit/indirector/certificate/file.rb
index 159a87606..18fe9a1c3 100755
--- a/spec/unit/indirector/certificate/file.rb
+++ b/spec/unit/indirector/certificate/file.rb
@@ -8,96 +8,12 @@ require File.dirname(__FILE__) + '/../../../spec_helper'
require 'puppet/indirector/certificate/file'
describe Puppet::SSL::Certificate::File do
- before do
- @file = Puppet::SSL::Certificate::File.new
- @cert = Puppet::SSL::Certificate.new("myname")
- Puppet.settings.stubs(:value).with(@file.class.directory_setting).returns "/test/dir"
- @path = "/test/dir/myname.pem"
- end
-
it "should have documentation" do
Puppet::SSL::Certificate::File.doc.should be_instance_of(String)
end
-
- describe "when choosing the location for certificates" do
- it "should set them in the :certdir, with the certificate name plus '.pem'" do
- @file.path(@cert.name).should == @path
- end
- end
-
- describe "when finding certificates on disk" do
- describe "and no certificate is present" do
- before do
- FileTest.expects(:exist?).with(@path).returns false
- end
-
- it "should return nil" do
- @file.find(@cert.name).should be_nil
- end
- end
-
- describe "and a certificate is present" do
- before do
- FileTest.expects(:exist?).with(@path).returns true
- end
-
- it "should return an instance of the model, which it should use to read the certificate" do
- cert = mock 'cert'
- Puppet::SSL::Certificate.expects(:new).with("myname").returns cert
- cert.expects(:read).with(@path)
- @file.find("myname").should equal(cert)
- end
- end
- end
-
- describe "when saving certificates to disk" do
- it "should fail if the directory is absent" do
- FileTest.expects(:directory?).with(File.dirname(@path)).returns false
- lambda { @file.save(@cert) }.should raise_error(Puppet::Error)
- end
-
- it "should fail if the directory is not writeable" do
- FileTest.stubs(:directory?).returns true
- FileTest.expects(:writable?).with(File.dirname(@path)).returns false
- lambda { @file.save(@cert) }.should raise_error(Puppet::Error)
- end
-
- it "should save to the path the output of converting the certificate to a string" do
- FileTest.stubs(:directory?).returns true
- FileTest.stubs(:writable?).returns true
-
- fh = mock 'filehandle'
- File.expects(:open).with(@path, "w").yields(fh)
-
- @cert.expects(:to_s).returns "mycert"
-
- fh.expects(:print).with("mycert")
-
- @file.save(@cert)
-
- end
- end
-
- describe "when destroying certificates" do
- describe "that do not exist" do
- before do
- FileTest.expects(:exist?).with(@path).returns false
- end
-
- it "should fail" do
- lambda { @file.destroy(@cert) }.should raise_error(Puppet::Error)
- end
- end
-
- describe "that exist" do
- before do
- FileTest.expects(:exist?).with(@path).returns true
- end
- it "should unlink the certificate file" do
- File.expects(:unlink).with(@path)
- @file.destroy(@cert)
- end
- end
+ it "should use the :certdir as the collection directory" do
+ Puppet.settings.expects(:value).with(:certdir).returns "/cert/dir"
+ Puppet::SSL::Certificate::File.collection_directory.should == "/cert/dir"
end
end
diff --git a/spec/unit/indirector/key/file.rb b/spec/unit/indirector/key/file.rb
index b9e9e2b11..add80b26c 100755
--- a/spec/unit/indirector/key/file.rb
+++ b/spec/unit/indirector/key/file.rb
@@ -8,158 +8,67 @@ require File.dirname(__FILE__) + '/../../../spec_helper'
require 'puppet/indirector/key/file'
describe Puppet::SSL::Key::File do
- it "should be a subclass of the File terminus class" do
- Puppet::SSL::Key::File.superclass.should equal(Puppet::Indirector::File)
- end
-
it "should have documentation" do
Puppet::SSL::Key::File.doc.should be_instance_of(String)
end
- describe "when managing keys on disk" do
- before do
- @file = Puppet::SSL::Key::File.new
- end
-
- describe "and choosing the location" do
- describe "for certificate authority keys" do
- before do
- @private_key = "/path/to/private/ca/key"
- @public_key = "/path/to/public/ca/key"
- Puppet.settings.stubs(:value).with(:cakey).returns @private_key
- Puppet.settings.stubs(:value).with(:capub).returns @public_key
- end
-
- it "should use the :cakey as the private key location and :capub for the public key location" do
- File.expects(:open).with(@private_key, "w")
- File.expects(:open).with(@private_key, "w")
-
- key = stub 'key', :name => :ca
-
- @file.save(key)
- end
- end
-
- describe "for normal keys" do
- before do
- @name = "myhost"
- end
-
- it "should save private key to the :privatekeydir with the file named after the key name plus '.pem'"
-
- it "should save the public key to the :publickeydir with the file named after the key name plus '.pem'"
- end
- end
-
- it "should be able to find keys saved to disk"
-
- it "should convert found keys to instances of OpenSSL::PKey::RSA"
-
- it "should be able to save keys to disk"
-
- it "should save keys in pem format"
-
- it "should save both public and private keys"
-
- it "should be able to remove keys stored on disk"
-
- it "should remove both public and private keys when the key is destroyed"
-
- it "should fail when attempting to remove missing keys"
+ it "should use the :privatekeydir as the collection directory" do
+ Puppet.settings.expects(:value).with(:privatekeydir).returns "/key/dir"
+ Puppet::SSL::Key::File.collection_directory.should == "/key/dir"
end
- describe "when choosing a path for a ca key" do
+ describe "when managing private keys" do
+ before do
+ @private = "/private/key/dir"
+ @public = "/public/key/dir"
+ Puppet.settings.stubs(:value).with(:privatekeydir).returns @private
+ Puppet.settings.stubs(:value).with(:publickeydir).returns @public
+ Puppet.settings.stubs(:use)
- it "should use the cadir" do
- pending "eh"
- Puppet.settings.stubs(:value).with(:cadir).returns("/dir")
- @file.path(@name).should =~ /^\/dir/
- end
+ @searcher = Puppet::SSL::Key::File.new
- it "should use 'ca_key.pem' as the file name" do
- pending "eh"
- @file.path(@name).should =~ /ca_key\.pem$/
- end
- end
+ @privatekey = File.join(@private, "myname" + ".pem")
+ @publickey = File.join(@public, "myname" + ".pem")
- describe "when choosing a path for a non-ca key" do
- before do
- @name = :publickey
- end
+ @public_key = stub 'public_key'
+ @real_key = stub 'sslkey', :public_key => @public_key
- it "should use the privatekeydir" do
- pending "eh"
- Puppet.settings.stubs(:value).with(:publickeydir).returns("/dir")
- @file.path(@name).should =~ /^\/dir/
+ @key = stub 'key', :name => "myname", :content => @real_key
end
- it "should use the key name with the pem file extension" do
- pending "eh"
- @file.path(@name).should =~ /#{@name}\.pem$/
- end
- end
+ it "should save the public key when saving the private key" do
+ FileTest.stubs(:directory?).returns true
+ FileTest.stubs(:writable?).returns true
- describe "when saving" do
- before do
- Puppet.settings.stubs(:value).with(:publickeydir).returns("/dir")
- @key = stub "key", :name => "foo"
- end
+ File.stubs(:open).with(@privatekey, "w")
- it "should store the private key to disk in pem format in the privatekey directory" do
- pending "eh"
- @key.expects(:to_pem).returns(:data)
- @path = "/dir/foo.pem"
- filehandle = mock "filehandle"
- File.expects(:open).with(@path, "w").yields(filehandle)
- filehandle.expects(:print).with(:data)
- @file.save(@key)
- end
+ fh = mock 'filehandle'
- it "should store the public key to disk in pem format in the publickey directory"
- end
+ File.expects(:open).with(@publickey, "w").yields fh
+ @public_key.expects(:to_pem).returns "my pem"
- describe "when finding a key by name" do
- before do
- Puppet.settings.stubs(:value).with(:publickeydir).returns("/dir")
- @name = "foo"
- end
+ fh.expects(:print).with "my pem"
- it "should return the key as a key object on success" do
- pending "eh"
- @path = "/dir/foo.pem"
- FileTest.stubs(:exists?).with(@path).returns(true)
- File.stubs(:read).with(@path).returns(:data)
- OpenSSL::PKey::RSA.expects(:new).with(:data).returns(:mykey)
- @file.find(@name).should == :mykey
+ @searcher.save(@key)
end
- it "should return 'nil' on failure" do
- pending "eh"
- @path = "/dir/foo.pem"
- FileTest.stubs(:exists?).with(@path).returns(false)
- @file.find(@name).should == nil
- end
- end
+ it "should destroy the public key when destroying the private key" do
+ File.stubs(:unlink).with(@privatekey)
+ FileTest.stubs(:exist?).with(@privatekey).returns true
+ FileTest.expects(:exist?).with(@publickey).returns true
+ File.expects(:unlink).with(@publickey)
- describe "when removing a key" do
- before do
- Puppet.settings.stubs(:value).with(:publickeydir).returns("/dir")
- @name = "foo"
+ @searcher.destroy(@key)
end
- it "should remove the key from disk and return true" do
- pending "eh"
- @path = "/dir/foo.pem"
- FileTest.stubs(:exists?).with(@path).returns(true)
- File.stubs(:unlink).with(@path).returns(true)
- @file.destroy(@name).should == true
- end
+ it "should not fail if the public key does not exist when deleting the private key" do
+ File.stubs(:unlink).with(@privatekey)
+
+ FileTest.stubs(:exist?).with(@privatekey).returns true
+ FileTest.expects(:exist?).with(@publickey).returns false
+ File.expects(:unlink).with(@publickey).never
- it "should return an exception on failure" do
- pending "eh"
- @path = "/dir/foo.pem"
- FileTest.stubs(:exists?).with(@path).returns(false)
- @file.destroy(@name).should == nil
+ @searcher.destroy(@key)
end
end
end
diff --git a/spec/unit/indirector/ssl_file.rb b/spec/unit/indirector/ssl_file.rb
new file mode 100755
index 000000000..5c148a967
--- /dev/null
+++ b/spec/unit/indirector/ssl_file.rb
@@ -0,0 +1,130 @@
+#!/usr/bin/env ruby
+#
+# Created by Luke Kanies on 2008-3-10.
+# Copyright (c) 2007. All rights reserved.
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+require 'puppet/indirector/ssl_file'
+
+describe Puppet::Indirector::SslFile do
+ before do
+ @indirection = stub 'indirection', :name => :testing
+ Puppet::Indirector::Indirection.expects(:instance).with(:testing).returns(@indirection)
+ @file_class = Class.new(Puppet::Indirector::SslFile) do
+ def self.to_s
+ "Testing::Mytype"
+ end
+ end
+
+ @setting = :mydir
+ @file_class.store_in @setting
+ @path = "/my/directory"
+ Puppet.settings.stubs(:[]).with(@setting).returns(@path)
+ end
+
+ it "should use ssl upon initialization" do
+ Puppet.settings.expects(:use).with(:ssl)
+ @file_class.new
+ end
+
+ it "should fail if no store directory has been set" do
+ @file_class.store_in nil
+ lambda { @file_class.collection_directory }.should raise_error(Puppet::DevError)
+ end
+
+ describe "when managing ssl files" do
+ before do
+ Puppet.settings.stubs(:use)
+ @searcher = @file_class.new
+
+ @cert = stub 'certificate', :name => "myname"
+ @certpath = File.join(@path, "myname" + ".pem")
+ end
+
+ describe "when choosing the location for certificates" do
+ it "should set them in the setting directory, with the certificate name plus '.pem'" do
+ @searcher.path(@cert.name).should == @certpath
+ end
+ end
+
+ describe "when finding certificates on disk" do
+ describe "and no certificate is present" do
+ before do
+ FileTest.expects(:exist?).with(@certpath).returns false
+ end
+
+ it "should return nil" do
+ @searcher.find(@cert.name).should be_nil
+ end
+ end
+
+ describe "and a certificate is present" do
+ before do
+ FileTest.expects(:exist?).with(@certpath).returns true
+ end
+
+ it "should return an instance of the model, which it should use to read the certificate" do
+ cert = mock 'cert'
+ model = mock 'model'
+ @file_class.stubs(:model).returns model
+
+ model.expects(:new).with("myname").returns cert
+ cert.expects(:read).with(@certpath)
+ @searcher.find("myname").should equal(cert)
+ end
+ end
+ end
+
+ describe "when saving certificates to disk" do
+ it "should fail if the directory is absent" do
+ FileTest.expects(:directory?).with(File.dirname(@certpath)).returns false
+ lambda { @searcher.save(@cert) }.should raise_error(Puppet::Error)
+ end
+
+ it "should fail if the directory is not writeable" do
+ FileTest.stubs(:directory?).returns true
+ FileTest.expects(:writable?).with(File.dirname(@certpath)).returns false
+ lambda { @searcher.save(@cert) }.should raise_error(Puppet::Error)
+ end
+
+ it "should save to the path the output of converting the certificate to a string" do
+ FileTest.stubs(:directory?).returns true
+ FileTest.stubs(:writable?).returns true
+
+ fh = mock 'filehandle'
+ File.expects(:open).with(@certpath, "w").yields(fh)
+
+ @cert.expects(:to_s).returns "mycert"
+
+ fh.expects(:print).with("mycert")
+
+ @searcher.save(@cert)
+
+ end
+ end
+
+ describe "when destroying certificates" do
+ describe "that do not exist" do
+ before do
+ FileTest.expects(:exist?).with(@certpath).returns false
+ end
+
+ it "should fail" do
+ lambda { @searcher.destroy(@cert) }.should raise_error(Puppet::Error)
+ end
+ end
+
+ describe "that exist" do
+ before do
+ FileTest.expects(:exist?).with(@certpath).returns true
+ end
+
+ it "should unlink the certificate file" do
+ File.expects(:unlink).with(@certpath)
+ @searcher.destroy(@cert)
+ end
+ end
+ end
+ end
+end