This is just moving the SSL setup and the authentication to the new plugable auth system for webrick.
Signed-off-by: Brice Figureau <[email protected]> --- lib/puppet/auth/handler/webrick/ssl.rb | 39 ++++++++++ lib/puppet/network/http/webrick.rb | 26 +------ lib/puppet/network/http/webrick/rest.rb | 9 +-- spec/unit/auth/handler/webrick/ssl_spec.rb | 107 +++++++++++++++++++++++++++ spec/unit/network/http/webrick/rest_spec.rb | 34 +++----- spec/unit/network/http/webrick_spec.rb | 75 ++---------------- 6 files changed, 171 insertions(+), 119 deletions(-) create mode 100644 lib/puppet/auth/handler/webrick/ssl.rb create mode 100644 spec/unit/auth/handler/webrick/ssl_spec.rb diff --git a/lib/puppet/auth/handler/webrick/ssl.rb b/lib/puppet/auth/handler/webrick/ssl.rb new file mode 100644 index 0000000..130feac --- /dev/null +++ b/lib/puppet/auth/handler/webrick/ssl.rb @@ -0,0 +1,39 @@ +require 'puppet/ssl/host' +require 'puppet/ssl/certificate' + +Puppet::Auth.new_handler(:ssl, :webrick) do + # Add all of the ssl cert information. + def self.setup + results = {} + + # Get the cached copy. We know it's been generated, too. + host = Puppet::SSL::Host.localhost + + raise Puppet::Error, "Could not retrieve certificate for #{host.name} and not running on a valid certificate authority" unless host.certificate + + results[:SSLPrivateKey] = host.key.content + results[:SSLCertificate] = host.certificate.content + results[:SSLStartImmediately] = true + results[:SSLEnable] = true + + raise Puppet::Error, "Could not find CA certificate" unless Puppet::SSL::Certificate.find(Puppet::SSL::CA_NAME) + + results[:SSLCACertificateFile] = Puppet[:localcacert] + results[:SSLVerifyClient] = OpenSSL::SSL::VERIFY_PEER + + results[:SSLCertificateStore] = host.ssl_store + + results + end + + def authenticate(ip, request) + result = [false, nil] + if cert = request.client_cert and nameary = cert.subject.to_a.find { |ary| ary[0] == "CN" } + result[1] = nameary[1] + result[0] = true + else + result[1] = resolve_node(ip) + end + result + end +end \ No newline at end of file diff --git a/lib/puppet/network/http/webrick.rb b/lib/puppet/network/http/webrick.rb index 8ed0b28..9b8c708 100644 --- a/lib/puppet/network/http/webrick.rb +++ b/lib/puppet/network/http/webrick.rb @@ -28,7 +28,7 @@ class Puppet::Network::HTTP::WEBrick arguments = {:BindAddress => args[:address], :Port => args[:port]} arguments.merge!(setup_logger) - arguments.merge!(setup_ssl) + arguments.merge!(Puppet::Auth.handler(:webrick).setup) @server = WEBrick::HTTPServer.new(arguments) @server.listeners.each { |l| l.start_immediately = false } @@ -91,30 +91,6 @@ class Puppet::Network::HTTP::WEBrick ] end - # Add all of the ssl cert information. - def setup_ssl - results = {} - - # Get the cached copy. We know it's been generated, too. - host = Puppet::SSL::Host.localhost - - raise Puppet::Error, "Could not retrieve certificate for #{host.name} and not running on a valid certificate authority" unless host.certificate - - results[:SSLPrivateKey] = host.key.content - results[:SSLCertificate] = host.certificate.content - results[:SSLStartImmediately] = true - results[:SSLEnable] = true - - raise Puppet::Error, "Could not find CA certificate" unless Puppet::SSL::Certificate.find(Puppet::SSL::CA_NAME) - - results[:SSLCACertificateFile] = Puppet[:localcacert] - results[:SSLVerifyClient] = OpenSSL::SSL::VERIFY_PEER - - results[:SSLCertificateStore] = host.ssl_store - - results - end - private def setup_handlers diff --git a/lib/puppet/network/http/webrick/rest.rb b/lib/puppet/network/http/webrick/rest.rb index d5c146d..592e65c 100644 --- a/lib/puppet/network/http/webrick/rest.rb +++ b/lib/puppet/network/http/webrick/rest.rb @@ -5,6 +5,7 @@ require 'webrick' class Puppet::Network::HTTP::WEBrickREST < WEBrick::HTTPServlet::AbstractServlet include Puppet::Network::HTTP::Handler + include Puppet::Auth::Handler def initialize(server, handler) raise ArgumentError, "server is required" unless server @@ -68,13 +69,7 @@ class Puppet::Network::HTTP::WEBrickREST < WEBrick::HTTPServlet::AbstractServlet # If they have a certificate (which will almost always be true) # then we get the hostname from the cert, instead of via IP # info - result[:authenticated] = false - if cert = request.client_cert and nameary = cert.subject.to_a.find { |ary| ary[0] == "CN" } - result[:node] = nameary[1] - result[:authenticated] = true - else - result[:node] = resolve_node(result) - end + result[:authenticated], result[:node] = authenticate(result[:ip], request) result end diff --git a/spec/unit/auth/handler/webrick/ssl_spec.rb b/spec/unit/auth/handler/webrick/ssl_spec.rb new file mode 100644 index 0000000..2ab6a4d --- /dev/null +++ b/spec/unit/auth/handler/webrick/ssl_spec.rb @@ -0,0 +1,107 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../../../spec_helper' + +describe Puppet::Auth, "ssl webrick authentication handler" do + before(:each) do + Puppet[:auth] = "ssl" + end + + describe "when configuring webrick ssl" do + before do + @key = stub 'key', :content => "mykey" + @cert = stub 'cert', :content => "mycert" + @host = stub 'host', :key => @key, :certificate => @cert, :name => "yay", :ssl_store => "mystore" + + Puppet::SSL::Certificate.stubs(:find).with('ca').returns @cert + + Puppet::SSL::Host.stubs(:localhost).returns @host + end + + it "should use the key from the localhost SSL::Host instance" do + Puppet::SSL::Host.expects(:localhost).returns @host + @host.expects(:key).returns @key + + Puppet::Auth.handler(:webrick).setup[:SSLPrivateKey].should == "mykey" + end + + it "should configure the certificate" do + Puppet::Auth.handler(:webrick).setup[:SSLCertificate].should == "mycert" + end + + it "should fail if no CA certificate can be found" do + Puppet::SSL::Certificate.stubs(:find).with('ca').returns nil + + lambda { Puppet::Auth.handler(:webrick).setup }.should raise_error(Puppet::Error) + end + + it "should specify the path to the CA certificate" do + Puppet[:hostcrl] = 'false' + Puppet[:localcacert] = '/ca/crt' + + Puppet::Auth.handler(:webrick).setup[:SSLCACertificateFile].should == "/ca/crt" + end + + it "should start ssl immediately" do + Puppet::Auth.handler(:webrick).setup[:SSLStartImmediately].should be_true + end + + it "should enable ssl" do + Puppet::Auth.handler(:webrick).setup[:SSLEnable].should be_true + end + + it "should configure the verification method as 'OpenSSL::SSL::VERIFY_PEER'" do + Puppet::Auth.handler(:webrick).setup[:SSLVerifyClient].should == OpenSSL::SSL::VERIFY_PEER + end + + it "should add an x509 store" do + Puppet[:hostcrl] = '/my/crl' + + @host.expects(:ssl_store).returns "mystore" + + Puppet::Auth.handler(:webrick).setup[:SSLCertificateStore].should == "mystore" + end + + it "should set the certificate name to 'nil'" do + Puppet::Auth.handler(:webrick).setup[:SSLCertName].should be_nil + end + end + + describe "when authenticating a webrick HTTP client" do + before(:each) do + @handler = Class.new do + def self.name + "Puppet::Network::HTTP::WEBrickREST" + end + include Puppet::Auth::Handler + end.new + @ip = :foo + @request = stub('webrick http request', :query => {}, :peeraddr => %w{eh boo host ip}, :client_cert => nil) + end + + it "should set 'authenticated' to true if a certificate is present" do + cert = stub 'cert', :subject => [%w{CN host.domain.com}] + @request.stubs(:client_cert).returns cert + @handler.authenticate(@ip, @request)[0].should be_true + end + + it "should set 'authenticated' to false if no certificate is present" do + @request.stubs(:client_cert).returns nil + @handler.authenticate(@ip, @request)[0].should be_false + end + + it "should pass the client's certificate name to model method if a certificate is present" do + cert = stub 'cert', :subject => [%w{CN host.domain.com}] + @request.stubs(:client_cert).returns cert + @handler.authenticate(@ip, @request)[1].should == "host.domain.com" + end + + it "should resolve the node name with an ip address look-up if no certificate is present" do + @request.stubs(:client_cert).returns nil + + @handler.expects(:resolve_node).with(:foo).returns(:resolved_node) + + @handler.authenticate(@ip, @request)[1].should == :resolved_node + end + end +end diff --git a/spec/unit/network/http/webrick/rest_spec.rb b/spec/unit/network/http/webrick/rest_spec.rb index b00c62d..3bd5e91 100755 --- a/spec/unit/network/http/webrick/rest_spec.rb +++ b/spec/unit/network/http/webrick/rest_spec.rb @@ -10,6 +10,10 @@ describe Puppet::Network::HTTP::WEBrickREST do Puppet::Network::HTTP::WEBrickREST.ancestors.should be_include(Puppet::Network::HTTP::Handler) end + it "should include the Puppet::Auth::Handler module" do + Puppet::Network::HTTP::WEBrickREST.ancestors.should be_include(Puppet::Auth::Handler) + end + describe "when initializing" do it "should call the Handler's initialization hook with its provided arguments as the server and handler" do Puppet::Network::HTTP::WEBrickREST.any_instance.expects(:initialize_for_puppet).with(:server => "my", :handler => "arguments") @@ -152,29 +156,17 @@ describe Puppet::Network::HTTP::WEBrickREST do @handler.params(@request)[:ip].should == "ipaddress" end - it "should set 'authenticated' to true if a certificate is present" do - cert = stub 'cert', :subject => [%w{CN host.domain.com}] - @request.stubs(:client_cert).returns cert - @handler.params(@request)[:authenticated].should be_true - end - - it "should set 'authenticated' to false if no certificate is present" do - @request.stubs(:client_cert).returns nil - @handler.params(@request)[:authenticated].should be_false - end - - it "should pass the client's certificate name to model method if a certificate is present" do - cert = stub 'cert', :subject => [%w{CN host.domain.com}] - @request.stubs(:client_cert).returns cert - @handler.params(@request)[:node].should == "host.domain.com" + it "should ask auth plugin if client is authenticated" do + @request.stubs(:peeraddr).returns(%w{noidea dunno hostname ipaddress}) + @handler.expects(:authenticate).with("ipaddress", @request) + @handler.params(@request) end - it "should resolve the node name with an ip address look-up if no certificate is present" do - @request.stubs(:client_cert).returns nil - - @handler.expects(:resolve_node).returns(:resolved_node) - - @handler.params(@request)[:node].should == :resolved_node + it "should use authentication result from auth plugin" do + @request.stubs(:peeraddr).returns(%w{noidea dunno hostname ipaddress}) + @handler.stubs(:authenticate).with("ipaddress", @request).returns([:authenticated, :node_name]) + @handler.params(@request)[:authenticated].should == :authenticated + @handler.params(@request)[:node].should == :node_name end end end diff --git a/spec/unit/network/http/webrick_spec.rb b/spec/unit/network/http/webrick_spec.rb index 2a6ef22..e03d3c4 100755 --- a/spec/unit/network/http/webrick_spec.rb +++ b/spec/unit/network/http/webrick_spec.rb @@ -6,6 +6,7 @@ require File.dirname(__FILE__) + '/../../../spec_helper' require 'puppet/network/http' require 'puppet/network/http/webrick' +require 'puppet/network/handler' describe Puppet::Network::HTTP::WEBrick, "after initializing" do it "should not be listening" do @@ -19,7 +20,9 @@ describe Puppet::Network::HTTP::WEBrick, "when turning on listening" do [:mount, :start, :shutdown].each {|meth| @mock_webrick.stubs(meth)} WEBrick::HTTPServer.stubs(:new).returns(@mock_webrick) @server = Puppet::Network::HTTP::WEBrick.new - [:setup_logger, :setup_ssl].each {|meth| @server.stubs(meth).returns({})} # the empty hash is required because of how we're merging + @server.stubs(:setup_logger).returns({}) # the empty hash is required because of how we're merging + @auth = stub 'auth', :setup => {} + Puppet::Auth.stubs(:handler).with(:webrick).returns(@auth) @listen_params = { :address => "127.0.0.1", :port => 31337, :xmlrpc_handlers => [], :protocols => [ :rest ] } end @@ -64,8 +67,8 @@ describe Puppet::Network::HTTP::WEBrick, "when turning on listening" do @server.listen(@listen_params) end - it "should configure SSL for webrick" do - @server.expects(:setup_ssl).returns(:Ssl => :testing, :Other => :yay) + it "should configure authentication for webrick" do + @auth.expects(:setup).returns(:Ssl => :testing, :Other => :yay) WEBrick::HTTPServer.expects(:new).with {|args| args[:Ssl] == :testing and args[:Other] == :yay @@ -166,7 +169,9 @@ describe Puppet::Network::HTTP::WEBrick, "when turning off listening" do [:mount, :start, :shutdown].each {|meth| @mock_webrick.stubs(meth)} WEBrick::HTTPServer.stubs(:new).returns(@mock_webrick) @server = Puppet::Network::HTTP::WEBrick.new - [:setup_logger, :setup_ssl].each {|meth| @server.stubs(meth).returns({})} # the empty hash is required because of how we're merging + @server.stubs(:setup_logger).returns({}) # the empty hash is required because of how we're merging + @auth = stub 'auth', :setup => {} + Puppet::Auth.stubs(:handler).with(:webrick).returns(@auth) @listen_params = { :address => "127.0.0.1", :port => 31337, :handlers => [ :node, :catalog ], :protocols => [ :rest ] } end @@ -274,66 +279,4 @@ describe Puppet::Network::HTTP::WEBrick do ] end end - - describe "when configuring ssl" do - before do - @key = stub 'key', :content => "mykey" - @cert = stub 'cert', :content => "mycert" - @host = stub 'host', :key => @key, :certificate => @cert, :name => "yay", :ssl_store => "mystore" - - Puppet::SSL::Certificate.stubs(:find).with('ca').returns @cert - - Puppet::SSL::Host.stubs(:localhost).returns @host - end - - it "should use the key from the localhost SSL::Host instance" do - Puppet::SSL::Host.expects(:localhost).returns @host - @host.expects(:key).returns @key - - @server.setup_ssl[:SSLPrivateKey].should == "mykey" - end - - it "should configure the certificate" do - @server.setup_ssl[:SSLCertificate].should == "mycert" - end - - it "should fail if no CA certificate can be found" do - Puppet::SSL::Certificate.stubs(:find).with('ca').returns nil - - lambda { @server.setup_ssl }.should raise_error(Puppet::Error) - end - - it "should specify the path to the CA certificate" do - Puppet.settings.stubs(:value).returns "whatever" - Puppet.settings.stubs(:value).with(:hostcrl).returns 'false' - Puppet.settings.stubs(:value).with(:localcacert).returns '/ca/crt' - - @server.setup_ssl[:SSLCACertificateFile].should == "/ca/crt" - end - - it "should start ssl immediately" do - @server.setup_ssl[:SSLStartImmediately].should be_true - end - - it "should enable ssl" do - @server.setup_ssl[:SSLEnable].should be_true - end - - it "should configure the verification method as 'OpenSSL::SSL::VERIFY_PEER'" do - @server.setup_ssl[:SSLVerifyClient].should == OpenSSL::SSL::VERIFY_PEER - end - - it "should add an x509 store" do - Puppet.settings.stubs(:value).returns "whatever" - Puppet.settings.stubs(:value).with(:hostcrl).returns '/my/crl' - - @host.expects(:ssl_store).returns "mystore" - - @server.setup_ssl[:SSLCertificateStore].should == "mystore" - end - - it "should set the certificate name to 'nil'" do - @server.setup_ssl[:SSLCertName].should be_nil - end - end end -- 1.7.2.1 -- 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.
