+1 for inclusion in testing/master (TBD) On Tue, Dec 29, 2009 at 6:53 AM, Brice Figureau <[email protected]> wrote: > 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 <[email protected]> > --- > lib/puppet/application/puppetca.rb | 8 +- > lib/puppet/application/puppetd.rb | 33 +++++-- > lib/puppet/ssl/base.rb | 17 +++ > lib/puppet/ssl/certificate_authority.rb | 9 ++- > lib/puppet/ssl/certificate_authority/interface.rb | 28 ++++-- > lib/puppet/ssl/certificate_request.rb | 2 + > sbin/puppetca | 11 ++- > sbin/puppetd | 23 ++++- > spec/unit/application/puppetca.rb | 15 +++ > spec/unit/application/puppetd.rb | 75 +++++++++++++- > spec/unit/ssl/base.rb | 40 +++++++ > spec/unit/ssl/certificate_authority.rb | 37 ++++++- > spec/unit/ssl/certificate_authority/interface.rb | 114 > +++++++++++++++------ > spec/unit/ssl/certificate_request.rb | 14 +++- > 14 files changed, 367 insertions(+), 59 deletions(-) > create mode 100755 spec/unit/ssl/base.rb > > 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 > - �[email protected](@mode, :to => hosts) > + �[email protected](@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 > + �[email protected]_digest(:digest) > + > + �[email protected] == :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"]) > + �[email protected]_digest(:digest) > + > + �[email protected](:apply).with { |mode,to| to[:digest] == :digest} > + > + �[email protected] > + 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 9977607..2be018b 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 > + �[email protected] 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 > + �[email protected]_preinit > + > + �[email protected][:digest].should == :MD5 > + end > + > + it "should not fingerprint by default" do > + �[email protected]_preinit > + > + �[email protected][: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 > @@ -298,6 +313,13 @@ describe "puppetd" do > @puppetd.run_setup > end > > + it "should install a none ca location in fingerprint mode" do > + �[email protected](:[]).with(:fingerprint).returns(true) > + Puppet::SSL::Host.expects(:ca_location=).with(:none) > + > + �[email protected]_setup > + end > + > it "should tell the report handler to use REST" do > Puppet::Transaction::Report.expects(:terminus_class=).with(:rest) > > @@ -381,6 +403,14 @@ describe "puppetd" do > @puppetd.run_setup > end > > + it "should not wait for a certificate in fingerprint mode" do > + �[email protected](:[]).with(:fingerprint).returns(true) > + �[email protected](:[]).with(:waitforcert).returns(123) > + �[email protected](:wait_for_cert).never > + > + �[email protected]_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) > @@ -439,6 +469,13 @@ describe "puppetd" do > before :each do > @puppetd.agent = @agent > @puppetd.daemon = @daemon > + �[email protected](:[]).with(:fingerprint).returns(false) > + end > + > + it "should dispatch to fingerprint if --fingerprint is used" do > + �[email protected](:[]).with(:fingerprint).returns(true) > + > + �[email protected]_command.should == :fingerprint > end > > it "should dispatch to onetime if --onetime is used" do > @@ -447,7 +484,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 > @@ -515,7 +552,39 @@ describe "puppetd" do > end > end > > - describe "without --onetime" do > + describe "with --fingerprint" do > + before :each do > + �...@cert = stub_everything 'cert' > + > �[email protected](:[]).with(:fingerprint).returns(true) > + �[email protected](:[]).with(:digest).returns(:MD5) > + �...@host = stub_everything 'host' > + �[email protected](:host).returns(@host) > + end > + > + it "should fingerprint the certificate if it exists" do > + �[email protected](:certificate).returns(@cert) > + �[email protected](:fingerprint).with(:MD5) > + �[email protected] > + end > + > + it "should fingerprint the certificate request if no certificate > have been signed" do > + �[email protected](:certificate).returns(nil) > + �[email protected](:certificate_request).returns(@cert) > + �[email protected](:fingerprint).with(:MD5) > + �[email protected] > + end > + > + it "should display the fingerprint" do > + �[email protected](:certificate).returns(@cert) > + �[email protected](:fingerprint).with(:MD5).returns("DIGEST") > + > + Puppet.expects(:notice).with("DIGEST") > + > + �[email protected] > + 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" > + �[email protected](: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 > + �[email protected](:to_der).returns("DER") > + OpenSSL::Digest.expects(:hexdigest).with("MD5", "DER").returns > "digest" > + > + �[email protected] == "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" > + > + �[email protected](: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)) > - �[email protected](: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)) > + �[email protected](: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 > + �[email protected](:fingerprint) > + �[email protected]("myhost") > + end > + > + it "should delegate to the certificate fingerprinting" do > + �[email protected](:fingerprint) > + �[email protected]("myhost") > + end > + > + it "should propagate the digest algorithm to the certificate > fingerprinting system" do > + �[email protected](:fingerprint).with(:digest) > + �[email protected]("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) > - �[email protected](:generate, :all) > + �[email protected](:generate, :to => :all) > end > > it "should set its subjects using the settor" do > @class.any_instance.expects(:subjects=).with(:all) > - �[email protected](:generate, :all) > + �[email protected](: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 > - �[email protected](:generate, :all).method.should == :generate > + �[email protected](: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 > - �[email protected](:generate, :all).subjects.should == :all > + �[email protected](: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 > - �[email protected](:generate, :all).should respond_to(:apply) > + �[email protected](: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) > + �[email protected](: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) > > - �[email protected](:puts).with "host1" > - �[email protected](:puts).with "host2" > - �[email protected](:puts).with "- host3 (certificate > revoked)" > - �[email protected](:puts).with "+ host4" > + �[email protected](:puts).with "host1 (fingerprint)" > + �[email protected](:puts).with "host2 (fingerprint)" > + �[email protected](:puts).with "- host3 (fingerprint) > (certificate revoked)" > + �[email protected](: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} > + �[email protected](: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}) > > - �[email protected](:puts).with "host1" > - �[email protected](:puts).with "host2" > - �[email protected](:puts).with "+ host3" > - �[email protected](:puts).with "+ host4" > + �[email protected](:puts).with "host1 (fingerprint)" > + �[email protected](:puts).with "host2 (fingerprint)" > + �[email protected](:puts).with "+ host3 (fingerprint)" > + �[email protected](: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) > + > + �[email protected](:fingerprint).with("host1", :digest).returns > "fingerprint1" > + �[email protected](:puts).with "host1 fingerprint1" > + > + �[email protected](@ca) > + end > + > + describe "and :all was provided" do > + it "should fingerprint all certificates (including waiting > ones)" do > + �[email protected](:list).returns %w{host1} > + �[email protected](:waiting?).returns %w{host2} > + > + �...@applier = @class.new(:fingerprint, :to => :all) > + > + �[email protected](:fingerprint).with("host1", :MD5).returns > "fingerprint1" > + �[email protected](:puts).with "host1 fingerprint1" > + > + �[email protected](:fingerprint).with("host2", :MD5).returns > "fingerprint2" > + �[email protected](:puts).with "host2 fingerprint2" > + > + �[email protected](@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}) > + > + �[email protected](:fingerprint).with("host1", :MD5).returns > "fingerprint1" > + �[email protected](:puts).with "host1 fingerprint1" > + > + �[email protected](:fingerprint).with("host2", :MD5).returns > "fingerprint2" > + �[email protected](:puts).with "host2 fingerprint2" > + > + �[email protected](@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 > + �[email protected](:fingerprint) > + �[email protected](@key) > + end > + > + it "should display the fingerprint" do > + Puppet.stubs(:info) > + �[email protected](:fingerprint).returns("FINGERPRINT") > + Puppet.expects(:info).with { |s| s =~ /FINGERPRINT/ } > + �[email protected](@key) > + end > + > it "should return the generated request" do > @instance.generate(@key).should equal(@request) > end > -- > 1.6.5.2 > > -- > > You received this message because you are subscribed to the Google Groups > "Puppet Developers" group. > To post to this group, send email to [email protected]. > To unsubscribe from this group, send email to > [email protected]. > For more options, visit this group at > http://groups.google.com/group/puppet-dev?hl=en. > > >
-- ----------------------------------------------------------- The power of accurate observation is commonly called cynicism by those who have not got it. ~George Bernard Shaw ------------------------------------------------------------
-- You received this message because you are subscribed to the Google Groups "Puppet Developers" group. To post to this group, send email to [email protected]. To unsubscribe from this group, send email to [email protected]. For more options, visit this group at http://groups.google.com/group/puppet-dev?hl=en.
