[Pkg-puppet-devel] [SCM] Puppet packaging for Debian branch, upstream, updated. 0.25.5-639-g8f94f35

James Turnbull james at lovedthanlost.net
Wed Jul 14 10:29:51 UTC 2010


The following commit has been merged in the upstream branch:
commit 3e9677f00a09d0249713ed2fa503e42b07f6d978
Author: Brice Figureau <brice-puppet at daysofwonder.com>
Date:   Tue Dec 29 15:27:54 2009 +0100

    Feature #2839 - fingerprint certificate
    
    This patch adds several things:
     * certificate fingerprinting in --list mode
     * a puppetca action called "--fingerprint" to display fingerprints
    of given certificates (or all including CSR)
     * a --fingerprint puppetd option to display client certificates
     * each time a CSR is generated, its fingerprint is displayed in the log
    
    It is also possible to use --digest in puppetca and puppetd to specify a specific digest
    algorithm.
    
    Signed-off-by: Brice Figureau <brice-puppet at daysofwonder.com>

diff --git a/lib/puppet/application/puppetca.rb b/lib/puppet/application/puppetca.rb
index adc1a6f..7362f2a 100644
--- a/lib/puppet/application/puppetca.rb
+++ b/lib/puppet/application/puppetca.rb
@@ -6,7 +6,7 @@ Puppet::Application.new(:puppetca) do
 
     should_parse_config
 
-    attr_accessor :mode, :all, :ca
+    attr_accessor :mode, :all, :ca, :digest
 
     def find_mode(opt)
         modes = Puppet::SSL::CertificateAuthority::Interface::INTERFACE_METHODS
@@ -22,6 +22,10 @@ Puppet::Application.new(:puppetca) do
         @all = true
     end
 
+    option("--digest DIGEST") do |arg|
+        @digest = arg
+    end
+
     option("--debug", "-d") do |arg|
         Puppet::Util::Log.level = :debug
     end
@@ -44,7 +48,7 @@ Puppet::Application.new(:puppetca) do
         end
         begin
             @ca.apply(:revoke, :to => hosts) if @mode == :destroy
-            @ca.apply(@mode, :to => hosts)
+            @ca.apply(@mode, :to => hosts, :digest => @digest)
         rescue => detail
             puts detail.backtrace if Puppet[:trace]
             puts detail.to_s
diff --git a/lib/puppet/application/puppetd.rb b/lib/puppet/application/puppetd.rb
index c99b9ea..ed2c450 100644
--- a/lib/puppet/application/puppetd.rb
+++ b/lib/puppet/application/puppetd.rb
@@ -9,7 +9,7 @@ Puppet::Application.new(:puppetd) do
 
     should_parse_config
 
-    attr_accessor :explicit_waitforcert, :args, :agent, :daemon
+    attr_accessor :explicit_waitforcert, :args, :agent, :daemon, :host
 
     preinit do
         # Do an initial trap, so that cancels don't get a stack trace.
@@ -30,7 +30,9 @@ Puppet::Application.new(:puppetd) do
             :disable => false,
             :client => true,
             :fqdn => nil,
-            :serve => []
+            :serve => [],
+            :digest => :MD5,
+            :fingerprint => false,
         }.each do |opt,val|
             options[opt] = val
         end
@@ -49,6 +51,9 @@ Puppet::Application.new(:puppetd) do
     option("--test","-t")
     option("--verbose","-v")
 
+    option("--fingerprint")
+    option("--digest DIGEST")
+
     option("--serve HANDLER", "-s") do |arg|
         if Puppet::Network::Handler.handler(arg)
             options[:serve] << arg.to_sym
@@ -92,10 +97,20 @@ Puppet::Application.new(:puppetd) do
     end
 
     dispatch do
+        return :fingerprint if options[:fingerprint]
         return :onetime if options[:onetime]
         return :main
     end
 
+    command(:fingerprint) do
+        unless cert = host.certificate || host.certificate_request
+           $stderr.puts "Fingerprint asked but no certificate nor certificate request have yet been issued"
+           exit(1)
+           return
+        end
+        Puppet.notice cert.fingerprint(options[:digest])
+    end
+
     command(:onetime) do
         unless options[:client]
             $stderr.puts "onetime is specified but there is no client"
@@ -220,10 +235,10 @@ Puppet::Application.new(:puppetd) do
 
         Puppet.settings.use :main, :puppetd, :ssl
 
-        # We need to specify a ca location for things to work, but
-        # until the REST cert transfers are working, it needs to
-        # be local.
-        Puppet::SSL::Host.ca_location = :remote
+        # We need to specify a ca location for things to work
+        # in fingerprint mode we just need access to the local files and
+        # we don't need a ca.
+        Puppet::SSL::Host.ca_location = options[:fingerprint] ? :none : :remote
 
         Puppet::Transaction::Report.terminus_class = :rest
 
@@ -246,8 +261,10 @@ Puppet::Application.new(:puppetd) do
             @daemon.daemonize
         end
 
-        host = Puppet::SSL::Host.new
-        cert = host.wait_for_cert(options[:waitforcert])
+        @host = Puppet::SSL::Host.new
+        unless options[:fingerprint]
+            cert = @host.wait_for_cert(options[:waitforcert])
+        end
 
         @objects = []
 
diff --git a/lib/puppet/ssl/base.rb b/lib/puppet/ssl/base.rb
index d67861f..6c74b75 100644
--- a/lib/puppet/ssl/base.rb
+++ b/lib/puppet/ssl/base.rb
@@ -54,6 +54,23 @@ class Puppet::SSL::Base
         content.to_text
     end
 
+    def fingerprint(md = :MD5)
+        require 'openssl/digest'
+
+        # ruby 1.8.x openssl digest constants are string
+        # but in 1.9.x they are symbols
+        mds = md.to_s.upcase
+        if OpenSSL::Digest.constants.include?(mds)
+            md = mds
+        elsif OpenSSL::Digest.constants.include?(mds.to_sym)
+            md = mds.to_sym
+        else
+            raise ArgumentError, "#{md} is not a valid digest algorithm for fingerprinting certificate #{name}"
+        end
+
+        OpenSSL::Digest.hexdigest(md, content.to_der).scan(/../).join(':').upcase
+    end
+
     private
 
     def wrapped_class
diff --git a/lib/puppet/ssl/certificate_authority.rb b/lib/puppet/ssl/certificate_authority.rb
index 8e4fd7a..9fe67cc 100644
--- a/lib/puppet/ssl/certificate_authority.rb
+++ b/lib/puppet/ssl/certificate_authority.rb
@@ -53,7 +53,7 @@ class Puppet::SSL::CertificateAuthority
         unless options[:to]
             raise ArgumentError, "You must specify the hosts to apply to; valid values are an array or the symbol :all"
         end
-        applier = Interface.new(method, options[:to])
+        applier = Interface.new(method, options)
 
         applier.apply(self)
     end
@@ -291,6 +291,13 @@ class Puppet::SSL::CertificateAuthority
         end
     end
 
+    def fingerprint(name, md = :MD5)
+        unless cert = Puppet::SSL::Certificate.find(name) || Puppet::SSL::CertificateRequest.find(name)
+            raise ArgumentError, "Could not find a certificate or csr for %s" % name
+        end
+        cert.fingerprint(md)
+    end
+
     # List the waiting certificate requests.
     def waiting?
         Puppet::SSL::CertificateRequest.search("*").collect { |r| r.name }
diff --git a/lib/puppet/ssl/certificate_authority/interface.rb b/lib/puppet/ssl/certificate_authority/interface.rb
index 3f91434..d2dc7b9 100644
--- a/lib/puppet/ssl/certificate_authority/interface.rb
+++ b/lib/puppet/ssl/certificate_authority/interface.rb
@@ -2,11 +2,11 @@
 # on the CA.  It's only used by the 'puppetca' executable, and its
 # job is to provide a CLI-like interface to the CA class.
 class Puppet::SSL::CertificateAuthority::Interface
-    INTERFACE_METHODS = [:destroy, :list, :revoke, :generate, :sign, :print, :verify]
+    INTERFACE_METHODS = [:destroy, :list, :revoke, :generate, :sign, :print, :verify, :fingerprint]
 
     class InterfaceError < ArgumentError; end
 
-    attr_reader :method, :subjects
+    attr_reader :method, :subjects, :digest
 
     # Actually perform the work.
     def apply(ca)
@@ -38,9 +38,10 @@ class Puppet::SSL::CertificateAuthority::Interface
         end
     end
 
-    def initialize(method, subjects)
+    def initialize(method, options)
         self.method = method
-        self.subjects = subjects
+        self.subjects = options[:to]
+        @digest = options[:digest] || :MD5
     end
 
     # List the hosts.
@@ -67,11 +68,11 @@ class Puppet::SSL::CertificateAuthority::Interface
                 invalid = details.to_s
             end
             if not invalid and signed.include?(host)
-                puts "+ " + host
+                puts "+ #{host} (#{ca.fingerprint(host, @digest)})"
             elsif invalid
-                puts "- " + host + " (" + invalid + ")"
+                puts "- #{host} (#{ca.fingerprint(host, @digest)}) (#{invalid})"
             else
-                puts host
+                puts "#{host} (#{ca.fingerprint(host, @digest)})"
             end
         end
     end
@@ -84,7 +85,7 @@ class Puppet::SSL::CertificateAuthority::Interface
 
     # Print certificate information.
     def print(ca)
-        (subjects == :all ? ca.list : subjects).each do |host|
+        (subjects == :all ? ca.list  : subjects).each do |host|
             if value = ca.print(host)
                 puts value
             else
@@ -93,6 +94,17 @@ class Puppet::SSL::CertificateAuthority::Interface
         end
     end
 
+    # Print certificate information.
+    def fingerprint(ca)
+        (subjects == :all ? ca.list + ca.waiting?: subjects).each do |host|
+            if value = ca.fingerprint(host, @digest)
+                puts "#{host} #{value}"
+            else
+                Puppet.err "Could not find certificate for %s" % host
+            end
+        end
+    end
+
     # Sign a given certificate.
     def sign(ca)
         list = subjects == :all ? ca.waiting? : subjects
diff --git a/lib/puppet/ssl/certificate_request.rb b/lib/puppet/ssl/certificate_request.rb
index 4008aba..f18fe4a 100644
--- a/lib/puppet/ssl/certificate_request.rb
+++ b/lib/puppet/ssl/certificate_request.rb
@@ -43,6 +43,8 @@ class Puppet::SSL::CertificateRequest < Puppet::SSL::Base
         raise Puppet::Error, "CSR sign verification failed; you need to clean the certificate request for %s on the server" % name unless csr.verify(key.public_key)
 
         @content = csr
+        Puppet.info "Certificate Request fingerprint (md5): #{fingerprint}"
+        @content
     end
 
     def save(args = {})
diff --git a/sbin/puppetca b/sbin/puppetca
index 27ba916..eab594b 100755
--- a/sbin/puppetca
+++ b/sbin/puppetca
@@ -10,7 +10,8 @@
 #
 #   puppetca [-h|--help] [-V|--version] [-d|--debug] [-v|--verbose]
 #               [-g|--generate] [-l|--list] [-s|--sign] [-r|--revoke]
-#               [-p|--print] [-c|--clean] [--verify] [host]
+#               [-p|--print] [-c|--clean] [--verify] [--digest DIGEST]
+#               [--fingerprint] [host]
 #
 # = Description
 #
@@ -35,6 +36,11 @@
 #   Operate on all items.  Currently only makes sense with '--sign',
 #   '--clean', or '--list'.
 #
+# digest::
+#   Set the digest for fingerprinting (defaults to md5). Valid values depends
+#   on your openssl and openssl ruby extension version, but should contain at
+#   least md5, sha1, md2, sha256.
+#
 # clean::
 #    Remove all files related to a host from puppetca's storage. This is
 #    useful when rebuilding hosts, since new certificate signing requests
@@ -62,6 +68,9 @@
 # print::
 #   Print the full-text version of a host's certificate.
 #
+# fingerprint::
+#   Print the DIGEST (defaults to md5) fingerprint of a host's certificate.
+#
 # revoke::
 #   Revoke the certificate of a client. The certificate can be specified
 #   either by its serial number, given as a decimal number or a hexadecimal
diff --git a/sbin/puppetd b/sbin/puppetd
index bf7d028..fd78dc6 100755
--- a/sbin/puppetd
+++ b/sbin/puppetd
@@ -12,7 +12,8 @@
 #       [--detailed-exitcodes] [--disable] [--enable]
 #       [-h|--help] [--fqdn <host name>] [-l|--logdest syslog|<file>|console]
 #       [-o|--onetime] [--serve <handler>] [-t|--test] [--noop]
-#       [-V|--version] [-v|--verbose] [-w|--waitforcert <seconds>]
+#       [--digest <digest>] [--fingerprint] [-V|--version]
+#       [-v|--verbose] [-w|--waitforcert <seconds>]
 #
 # = Description
 #
@@ -35,7 +36,7 @@
 # configuration every 30 minutes.
 #
 # Some flags are meant specifically for interactive use -- in particular,
-# +test+ and +tags+ are useful.  +test+ enables verbose logging, causes
+# +test+, +tags+ or +fingerprint+ are useful. +test+ enables verbose logging, causes
 # the daemon to stay in the foreground, exits if the server's configuration is
 # invalid (this happens if, for instance, you've left a syntax error on the
 # server), and exits after running the configuration once (rather than hanging
@@ -51,6 +52,15 @@
 # which would only apply that small portion of the configuration during your
 # testing, rather than applying the whole thing.
 #
+# +fingerprint+ is a one-time flag. In this mode +puppetd+ will run once and
+# display on the console (and in the log) the current certificate (or certificate
+# request) fingerprint. Providing the +--digest+ option allows to use a different
+# digest algorithm to generate the fingerprint. The main use is to verify that
+# before signing a certificate request on the master, the certificate request the
+# master received is the same as the one the client sent (to prevent against
+# man-in-the-middle attacks when signing certificates).
+# 
+#
 # = Options
 #
 # Note that any configuration parameter that's valid in the configuration file
@@ -72,6 +82,11 @@
 # debug::
 #   Enable full debugging.
 #
+# digest::
+#   Change the certificate fingerprinting digest algorithm. The default is MD5.
+#   Valid values depends on the version of OpenSSL installed, but should always
+#   at least contain MD5, MD2, SHA1 and SHA256.
+#
 # detailed-exitcodes::
 #   Provide transaction information via exit codes.  If this is enabled, an
 #   exit code of '2' means there were changes, and an exit code of '4' means
@@ -119,6 +134,10 @@
 #   Run the configuration once, rather than as a long-running daemon.  This is
 #   useful for interactively running puppetd.
 #
+# fingerprint::
+#   Display the current certificate or certificate signing request fingerprint
+#   and then exit. Use the +--digest+ option to change the digest algorithm used.
+#
 # serve::
 #   Start another type of server.  By default, +puppetd+ will start
 #   a service handler that allows authenticated and authorized remote nodes to
diff --git a/spec/unit/application/puppetca.rb b/spec/unit/application/puppetca.rb
index 3a535f3..132a03c 100644
--- a/spec/unit/application/puppetca.rb
+++ b/spec/unit/application/puppetca.rb
@@ -39,6 +39,12 @@ describe "PuppetCA" do
         @puppetca.handle_debug(0)
     end
 
+    it "should set the fingerprint digest with the --digest option" do
+        @puppetca.handle_digest(:digest)
+
+        @puppetca.digest.should == :digest
+    end
+
     it "should set mode to :destroy for --clean" do
         @puppetca.handle_clean(0)
         @puppetca.mode.should == :destroy
@@ -129,6 +135,15 @@ describe "PuppetCA" do
             @puppetca.main
         end
 
+        it "should send the currently set digest" do
+            ARGV.stubs(:collect).returns(["host"])
+            @puppetca.handle_digest(:digest)
+
+            @ca.expects(:apply).with { |mode,to| to[:digest] == :digest}
+
+            @puppetca.main
+        end
+
         it "should delegate to ca.apply with current set mode" do
             @puppetca.mode = "currentmode"
             ARGV.stubs(:collect).returns(["host"])
diff --git a/spec/unit/application/puppetd.rb b/spec/unit/application/puppetd.rb
index dc061ea..246c399 100755
--- a/spec/unit/application/puppetd.rb
+++ b/spec/unit/application/puppetd.rb
@@ -34,6 +34,10 @@ describe "puppetd" do
         @puppetd.should respond_to(:onetime)
     end
 
+    it "should declare a fingerprint command" do
+        @puppetd.should respond_to(:fingerprint)
+    end
+
     it "should declare a preinit block" do
         @puppetd.should respond_to(:run_preinit)
     end
@@ -73,6 +77,17 @@ describe "puppetd" do
             @puppetd.options[:serve].should == []
         end
 
+        it "should use MD5 as default digest algorithm" do
+            @puppetd.run_preinit
+
+            @puppetd.options[:digest].should == :MD5
+        end
+
+        it "should not fingerprint by default" do
+            @puppetd.run_preinit
+
+            @puppetd.options[:fingerprint].should be_false
+        end
     end
 
     describe "when handling options" do
@@ -86,7 +101,7 @@ describe "puppetd" do
             @old_argv.each { |a| ARGV << a }
         end
 
-        [:centrallogging, :disable, :enable, :debug, :fqdn, :test, :verbose].each do |option|
+        [:centrallogging, :disable, :enable, :debug, :fqdn, :test, :verbose, :digest].each do |option|
             it "should declare handle_#{option} method" do
                 @puppetd.should respond_to("handle_#{option}".to_sym)
             end
@@ -299,6 +314,13 @@ describe "puppetd" do
             @puppetd.run_setup
         end
 
+        it "should install a none ca location in fingerprint mode" do
+            @puppetd.options.stubs(:[]).with(:fingerprint).returns(true)
+            Puppet::SSL::Host.expects(:ca_location=).with(:none)
+
+            @puppetd.run_setup
+        end
+
         it "should tell the report handler to use REST" do
             Puppet::Transaction::Report.expects(:terminus_class=).with(:rest)
 
@@ -382,6 +404,14 @@ describe "puppetd" do
             @puppetd.run_setup
         end
 
+        it "should not wait for a certificate in fingerprint mode" do
+            @puppetd.options.stubs(:[]).with(:fingerprint).returns(true)
+            @puppetd.options.stubs(:[]).with(:waitforcert).returns(123)
+            @host.expects(:wait_for_cert).never
+
+            @puppetd.run_setup
+        end
+
         it "should setup listen if told to and not onetime" do
             Puppet.stubs(:[]).with(:listen).returns(true)
             @puppetd.options.stubs(:[]).with(:onetime).returns(false)
@@ -440,6 +470,13 @@ describe "puppetd" do
         before :each do
             @puppetd.agent = @agent
             @puppetd.daemon = @daemon
+            @puppetd.options.stubs(:[]).with(:fingerprint).returns(false)
+        end
+
+        it "should dispatch to fingerprint if --fingerprint is used" do
+            @puppetd.options.stubs(:[]).with(:fingerprint).returns(true)
+
+            @puppetd.get_command.should == :fingerprint
         end
 
         it "should dispatch to onetime if --onetime is used" do
@@ -448,7 +485,7 @@ describe "puppetd" do
             @puppetd.get_command.should == :onetime
         end
 
-        it "should dispatch to main if --onetime is not used" do
+        it "should dispatch to main if --onetime and --fingerprint are not used" do
             @puppetd.options.stubs(:[]).with(:onetime).returns(false)
 
             @puppetd.get_command.should == :main
@@ -516,7 +553,39 @@ describe "puppetd" do
             end
         end
 
-        describe "without --onetime" do
+        describe "with --fingerprint" do
+            before :each do
+                @cert = stub_everything 'cert'
+                @puppetd.options.stubs(:[]).with(:fingerprint).returns(true)
+                @puppetd.options.stubs(:[]).with(:digest).returns(:MD5)
+                @host = stub_everything 'host'
+                @puppetd.stubs(:host).returns(@host)
+            end
+
+            it "should fingerprint the certificate if it exists" do
+                @host.expects(:certificate).returns(@cert)
+                @cert.expects(:fingerprint).with(:MD5)
+                @puppetd.fingerprint
+            end
+
+            it "should fingerprint the certificate request if no certificate have been signed" do
+                @host.expects(:certificate).returns(nil)
+                @host.expects(:certificate_request).returns(@cert)
+                @cert.expects(:fingerprint).with(:MD5)
+                @puppetd.fingerprint
+            end
+
+            it "should display the fingerprint" do
+                @host.stubs(:certificate).returns(@cert)
+                @cert.stubs(:fingerprint).with(:MD5).returns("DIGEST")
+
+                Puppet.expects(:notice).with("DIGEST")
+
+                @puppetd.fingerprint
+            end
+        end
+
+        describe "without --onetime and --fingerprint" do
             before :each do
                 Puppet.stubs(:notice)
                 @puppetd.options.stubs(:[]).with(:client)
diff --git a/spec/unit/ssl/base.rb b/spec/unit/ssl/base.rb
new file mode 100755
index 0000000..dfab3c8
--- /dev/null
+++ b/spec/unit/ssl/base.rb
@@ -0,0 +1,40 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+require 'puppet/ssl/certificate'
+
+class TestCertificate < Puppet::SSL::Base; end
+
+describe Puppet::SSL::Certificate do
+    before :each do
+        @base = TestCertificate.new("name")
+    end
+
+    describe "when fingerprinting content" do
+        before :each do
+            @cert = stub 'cert', :to_der => "DER"
+            @base.stubs(:content).returns(@cert)
+            OpenSSL::Digest.stubs(:constants).returns ["MD5", "DIGEST"]
+        end
+
+        it "should digest the certificate DER value and return a ':' seperated nibblet string" do
+            @cert.expects(:to_der).returns("DER")
+            OpenSSL::Digest.expects(:hexdigest).with("MD5", "DER").returns "digest"
+
+            @base.fingerprint.should == "DI:GE:ST"
+        end
+
+        it "should raise an error if the digest algorithm is not defined" do
+            OpenSSL::Digest.expects(:constants).returns []
+
+            lambda { @base.fingerprint }.should raise_error
+        end
+
+        it "should use the given digest algorithm" do
+            OpenSSL::Digest.expects(:hexdigest).with("DIGEST", "DER").returns "digest"
+
+            @base.fingerprint(:digest).should == "DI:GE:ST"
+        end
+    end
+end
\ No newline at end of file
diff --git a/spec/unit/ssl/certificate_authority.rb b/spec/unit/ssl/certificate_authority.rb
index 8011430..4d2303a 100755
--- a/spec/unit/ssl/certificate_authority.rb
+++ b/spec/unit/ssl/certificate_authority.rb
@@ -532,9 +532,9 @@ describe Puppet::SSL::CertificateAuthority do
                 lambda { @ca.apply(:generate) }.should raise_error(ArgumentError)
             end
 
-            it "should create an Interface instance with the specified method and the subjects" do
-                Puppet::SSL::CertificateAuthority::Interface.expects(:new).with(:generate, :hosts).returns(stub('applier', :apply => nil))
-                @ca.apply(:generate, :to => :hosts)
+            it "should create an Interface instance with the specified method and the options" do
+                Puppet::SSL::CertificateAuthority::Interface.expects(:new).with(:generate, :to => :host).returns(stub('applier', :apply => nil))
+                @ca.apply(:generate, :to => :host)
             end
 
             it "should apply the Interface with itself as the argument" do
@@ -583,6 +583,37 @@ describe Puppet::SSL::CertificateAuthority do
             end
         end
 
+        describe "and fingerprinting certificates" do
+            before :each do
+                @cert = stub 'cert', :name => "cert", :fingerprint => "DIGEST"
+                Puppet::SSL::Certificate.stubs(:find).with("myhost").returns @cert
+                Puppet::SSL::CertificateRequest.stubs(:find).with("myhost")
+            end
+
+            it "should raise an error if the certificate or CSR cannot be found" do
+                Puppet::SSL::Certificate.expects(:find).with("myhost").returns nil
+                Puppet::SSL::CertificateRequest.expects(:find).with("myhost").returns nil
+                lambda { @ca.fingerprint("myhost") }.should raise_error
+            end
+
+            it "should try to find a CSR if no certificate can be found" do
+                Puppet::SSL::Certificate.expects(:find).with("myhost").returns nil
+                Puppet::SSL::CertificateRequest.expects(:find).with("myhost").returns @cert
+                @cert.expects(:fingerprint)
+                @ca.fingerprint("myhost")
+            end
+
+            it "should delegate to the certificate fingerprinting" do
+                @cert.expects(:fingerprint)
+                @ca.fingerprint("myhost")
+            end
+
+            it "should propagate the digest algorithm to the certificate fingerprinting system" do
+                @cert.expects(:fingerprint).with(:digest)
+                @ca.fingerprint("myhost", :digest)
+            end
+        end
+
         describe "and verifying certificates" do
             before do
                 @store = stub 'store', :verify => true, :add_file => nil, :purpose= => nil, :add_crl => true, :flags= => nil
diff --git a/spec/unit/ssl/certificate_authority/interface.rb b/spec/unit/ssl/certificate_authority/interface.rb
index d741ec4..bcba298 100755
--- a/spec/unit/ssl/certificate_authority/interface.rb
+++ b/spec/unit/ssl/certificate_authority/interface.rb
@@ -9,7 +9,7 @@ describe "a normal interface method", :shared => true do
         @ca.expects(@method).with("host1")
         @ca.expects(@method).with("host2")
 
-        @applier = Puppet::SSL::CertificateAuthority::Interface.new(@method, %w{host1 host2})
+        @applier = Puppet::SSL::CertificateAuthority::Interface.new(@method, :to => %w{host1 host2})
 
         @applier.apply(@ca)
     end
@@ -20,7 +20,7 @@ describe "a normal interface method", :shared => true do
         @ca.expects(@method).with("host1")
         @ca.expects(@method).with("host2")
 
-        @applier = Puppet::SSL::CertificateAuthority::Interface.new(@method, :all)
+        @applier = Puppet::SSL::CertificateAuthority::Interface.new(@method, :to => :all)
 
         @applier.apply(@ca)
     end
@@ -33,30 +33,40 @@ describe Puppet::SSL::CertificateAuthority::Interface do
     describe "when initializing" do
         it "should set its method using its settor" do
             @class.any_instance.expects(:method=).with(:generate)
-            @class.new(:generate, :all)
+            @class.new(:generate, :to => :all)
         end
 
         it "should set its subjects using the settor" do
             @class.any_instance.expects(:subjects=).with(:all)
-            @class.new(:generate, :all)
+            @class.new(:generate, :to => :all)
+        end
+
+        it "should set the digest if given" do
+            interface = @class.new(:generate, :to => :all, :digest => :digest)
+            interface.digest.should == :digest
+        end
+
+        it "should set the digest to md5 if none given" do
+            interface = @class.new(:generate, :to => :all)
+            interface.digest.should == :MD5
         end
     end
 
     describe "when setting the method" do
         it "should set the method" do
-            @class.new(:generate, :all).method.should == :generate
+            @class.new(:generate, :to => :all).method.should == :generate
         end
 
         it "should fail if the method isn't a member of the INTERFACE_METHODS array" do
             Puppet::SSL::CertificateAuthority::Interface::INTERFACE_METHODS.expects(:include?).with(:thing).returns false
 
-            lambda { @class.new(:thing, :all) }.should raise_error(ArgumentError)
+            lambda { @class.new(:thing, :to => :all) }.should raise_error(ArgumentError)
         end
     end
 
     describe "when setting the subjects" do
         it "should set the subjects" do
-            @class.new(:generate, :all).subjects.should == :all
+            @class.new(:generate, :to => :all).subjects.should == :all
         end
 
         it "should fail if the subjects setting isn't :all or an array" do
@@ -65,7 +75,7 @@ describe Puppet::SSL::CertificateAuthority::Interface do
     end
 
     it "should have a method for triggering the application" do
-        @class.new(:generate, :all).should respond_to(:apply)
+        @class.new(:generate, :to => :all).should respond_to(:apply)
     end
 
     describe "when applying" do
@@ -75,7 +85,7 @@ describe Puppet::SSL::CertificateAuthority::Interface do
         end
 
         it "should raise InterfaceErrors" do
-            @applier = @class.new(:revoke, :all)
+            @applier = @class.new(:revoke, :to => :all)
 
             @ca.expects(:list).raises Puppet::SSL::CertificateAuthority::Interface::InterfaceError
 
@@ -83,7 +93,7 @@ describe Puppet::SSL::CertificateAuthority::Interface do
         end
 
         it "should log non-Interface failures rather than failing" do
-            @applier = @class.new(:revoke, :all)
+            @applier = @class.new(:revoke, :to => :all)
 
             @ca.expects(:list).raises ArgumentError
 
@@ -94,19 +104,19 @@ describe Puppet::SSL::CertificateAuthority::Interface do
 
         describe "with an empty array specified and the method is not list" do
             it "should fail" do
-                @applier = @class.new(:sign, [])
+                @applier = @class.new(:sign, :to => [])
                 lambda { @applier.apply(@ca) }.should raise_error(ArgumentError)
             end
         end
 
         describe ":generate" do
             it "should fail if :all was specified" do
-                @applier = @class.new(:generate, :all)
+                @applier = @class.new(:generate, :to => :all)
                 lambda { @applier.apply(@ca) }.should raise_error(ArgumentError)
             end
 
             it "should call :generate on the CA for each host specified" do
-                @applier = @class.new(:generate, %w{host1 host2})
+                @applier = @class.new(:generate, :to => %w{host1 host2})
 
                 @ca.expects(:generate).with("host1")
                 @ca.expects(:generate).with("host2")
@@ -141,7 +151,7 @@ describe Puppet::SSL::CertificateAuthority::Interface do
         describe ":sign" do
             describe "and an array of names was provided" do
                 before do
-                    @applier = @class.new(:sign, %w{host1 host2})
+                    @applier = @class.new(:sign, :to => %w{host1 host2})
                 end
 
                 it "should sign the specified waiting certificate requests" do
@@ -159,14 +169,14 @@ describe Puppet::SSL::CertificateAuthority::Interface do
                     @ca.expects(:sign).with("cert1")
                     @ca.expects(:sign).with("cert2")
 
-                    @applier = @class.new(:sign, :all)
+                    @applier = @class.new(:sign, :to => :all)
                     @applier.apply(@ca)
                 end
 
                 it "should fail if there are no waiting certificate requests" do
                     @ca.stubs(:waiting?).returns([])
 
-                    @applier = @class.new(:sign, :all)
+                    @applier = @class.new(:sign, :to => :all)
                     lambda { @applier.apply(@ca) }.should raise_error(Puppet::SSL::CertificateAuthority::Interface::InterfaceError)
                 end
             end
@@ -178,7 +188,7 @@ describe Puppet::SSL::CertificateAuthority::Interface do
                     @ca.expects(:waiting?).returns %w{host1 host2}
                     @ca.stubs(:verify)
 
-                    @applier = @class.new(:list, [])
+                    @applier = @class.new(:list, :to => [])
 
                     @applier.expects(:puts).with "host1\nhost2"
 
@@ -191,14 +201,15 @@ describe Puppet::SSL::CertificateAuthority::Interface do
                     @ca.expects(:waiting?).returns %w{host1 host2}
                     @ca.expects(:list).returns %w{host3 host4}
                     @ca.stubs(:verify)
+                    @ca.stubs(:fingerprint).returns "fingerprint"
                     @ca.expects(:verify).with("host3").raises(Puppet::SSL::CertificateAuthority::CertificateVerificationError.new(23), "certificate revoked")
 
-                    @applier = @class.new(:list, :all)
+                    @applier = @class.new(:list, :to => :all)
 
-                    @applier.expects(:puts).with "host1"
-                    @applier.expects(:puts).with "host2"
-                    @applier.expects(:puts).with "- host3 (certificate revoked)"
-                    @applier.expects(:puts).with "+ host4"
+                    @applier.expects(:puts).with "host1 (fingerprint)"
+                    @applier.expects(:puts).with "host2 (fingerprint)"
+                    @applier.expects(:puts).with "- host3 (fingerprint) (certificate revoked)"
+                    @applier.expects(:puts).with "+ host4 (fingerprint)"
 
                     @applier.apply(@ca)
                 end
@@ -208,14 +219,15 @@ describe Puppet::SSL::CertificateAuthority::Interface do
                 it "should print a string of all named hosts that have a waiting request" do
                     @ca.expects(:waiting?).returns %w{host1 host2}
                     @ca.expects(:list).returns %w{host3 host4}
+                    @ca.stubs(:fingerprint).returns "fingerprint"
                     @ca.stubs(:verify)
 
-                    @applier = @class.new(:list, %w{host1 host2 host3 host4})
+                    @applier = @class.new(:list, :to => %w{host1 host2 host3 host4})
 
-                    @applier.expects(:puts).with "host1"
-                    @applier.expects(:puts).with "host2"
-                    @applier.expects(:puts).with "+ host3"
-                    @applier.expects(:puts).with "+ host4"
+                    @applier.expects(:puts).with "host1 (fingerprint)"
+                    @applier.expects(:puts).with "host2 (fingerprint)"
+                    @applier.expects(:puts).with "+ host3 (fingerprint)"
+                    @applier.expects(:puts).with "+ host4 (fingerprint)"
 
                     @applier.apply(@ca)
                 end
@@ -227,7 +239,7 @@ describe Puppet::SSL::CertificateAuthority::Interface do
                 it "should print all certificates" do
                     @ca.expects(:list).returns %w{host1 host2}
 
-                    @applier = @class.new(:print, :all)
+                    @applier = @class.new(:print, :to => :all)
 
                     @ca.expects(:print).with("host1").returns "h1"
                     @applier.expects(:puts).with "h1"
@@ -241,7 +253,7 @@ describe Puppet::SSL::CertificateAuthority::Interface do
 
             describe "and an array of names was provided" do
                 it "should print each named certificate if found" do
-                    @applier = @class.new(:print, %w{host1 host2})
+                    @applier = @class.new(:print, :to => %w{host1 host2})
 
                     @ca.expects(:print).with("host1").returns "h1"
                     @applier.expects(:puts).with "h1"
@@ -253,7 +265,7 @@ describe Puppet::SSL::CertificateAuthority::Interface do
                 end
 
                 it "should log any named but not found certificates" do
-                    @applier = @class.new(:print, %w{host1 host2})
+                    @applier = @class.new(:print, :to => %w{host1 host2})
 
                     @ca.expects(:print).with("host1").returns "h1"
                     @applier.expects(:puts).with "h1"
@@ -265,5 +277,47 @@ describe Puppet::SSL::CertificateAuthority::Interface do
                 end
             end
         end
+
+        describe ":fingerprint" do
+            it "should fingerprint with the set digest algorithm" do
+                @applier = @class.new(:fingerprint, :to => %w{host1}, :digest => :digest)
+
+                @ca.expects(:fingerprint).with("host1", :digest).returns "fingerprint1"
+                @applier.expects(:puts).with "host1 fingerprint1"
+
+                @applier.apply(@ca)
+            end
+
+            describe "and :all was provided" do
+                it "should fingerprint all certificates (including waiting ones)" do
+                    @ca.expects(:list).returns %w{host1}
+                    @ca.expects(:waiting?).returns %w{host2}
+
+                    @applier = @class.new(:fingerprint, :to => :all)
+
+                    @ca.expects(:fingerprint).with("host1", :MD5).returns "fingerprint1"
+                    @applier.expects(:puts).with "host1 fingerprint1"
+
+                    @ca.expects(:fingerprint).with("host2", :MD5).returns "fingerprint2"
+                    @applier.expects(:puts).with "host2 fingerprint2"
+
+                    @applier.apply(@ca)
+                end
+            end
+
+            describe "and an array of names was provided" do
+                it "should print each named certificate if found" do
+                    @applier = @class.new(:fingerprint, :to => %w{host1 host2})
+
+                    @ca.expects(:fingerprint).with("host1", :MD5).returns "fingerprint1"
+                    @applier.expects(:puts).with "host1 fingerprint1"
+
+                    @ca.expects(:fingerprint).with("host2", :MD5).returns "fingerprint2"
+                    @applier.expects(:puts).with "host2 fingerprint2"
+
+                    @applier.apply(@ca)
+                end
+            end
+        end
     end
 end
diff --git a/spec/unit/ssl/certificate_request.rb b/spec/unit/ssl/certificate_request.rb
index 29bbc7b..a4eee92 100755
--- a/spec/unit/ssl/certificate_request.rb
+++ b/spec/unit/ssl/certificate_request.rb
@@ -106,7 +106,7 @@ describe Puppet::SSL::CertificateRequest do
         end
 
         it "should log that it is creating a new certificate request" do
-            Puppet.expects(:info)
+            Puppet.expects(:info).twice
             @instance.generate(@key)
         end
 
@@ -164,6 +164,18 @@ describe Puppet::SSL::CertificateRequest do
             lambda { @instance.generate(@key) }.should raise_error(Puppet::Error)
         end
 
+        it "should fingerprint the request" do
+            @instance.expects(:fingerprint)
+            @instance.generate(@key)
+        end
+
+        it "should display the fingerprint" do
+            Puppet.stubs(:info)
+            @instance.stubs(:fingerprint).returns("FINGERPRINT")
+            Puppet.expects(:info).with { |s| s =~ /FINGERPRINT/ }
+            @instance.generate(@key)
+        end
+
         it "should return the generated request" do
             @instance.generate(@key).should equal(@request)
         end

-- 
Puppet packaging for Debian



More information about the Pkg-puppet-devel mailing list