diff options
author | danielsdeleo <dan@getchef.com> | 2014-12-10 12:54:34 -0800 |
---|---|---|
committer | danielsdeleo <dan@getchef.com> | 2014-12-10 15:02:14 -0800 |
commit | 01c7e4dc402c3252a96ba05680747fe773b78f39 (patch) | |
tree | 52af8a549d70269b8398268f6049d33ba2bc53bf | |
parent | e809bb40b1340309c86edac9fb5cf7f179f8f7ec (diff) | |
download | chef-01c7e4dc402c3252a96ba05680747fe773b78f39.tar.gz |
Catch 'unknown protocol' errors in ssl fetch and explain them
The error message from OpenSSL when connecting to a non-ssl service is
confusing--it looks like a certificate validation failure. Catch the
error and explain what caused it.
-rw-r--r-- | lib/chef/knife/ssl_fetch.rb | 13 | ||||
-rw-r--r-- | spec/unit/knife/ssl_fetch_spec.rb | 53 |
2 files changed, 56 insertions, 10 deletions
diff --git a/lib/chef/knife/ssl_fetch.rb b/lib/chef/knife/ssl_fetch.rb index 5626a5610d..745aca5786 100644 --- a/lib/chef/knife/ssl_fetch.rb +++ b/lib/chef/knife/ssl_fetch.rb @@ -136,6 +136,19 @@ TRUST_TRUST remote_cert_chain.each do |cert| write_cert(cert) end + rescue OpenSSL::SSL::SSLError => e + # 'unknown protocol' usually means you tried to connect to a non-ssl + # service. We handle that specially here, any other error we let bubble + # up (probably a bug of some sort). + raise unless e.message.include?("unknown protocol") + + ui.error("The service at the given URI (#{uri}) does not accept SSL connections") + + if uri.scheme == "http" + https_uri = uri.to_s.sub(/^http/, 'https') + ui.error("Perhaps you meant to connect to '#{https_uri}'?") + end + exit 1 end diff --git a/spec/unit/knife/ssl_fetch_spec.rb b/spec/unit/knife/ssl_fetch_spec.rb index 24101dbe7a..cd0e423459 100644 --- a/spec/unit/knife/ssl_fetch_spec.rb +++ b/spec/unit/knife/ssl_fetch_spec.rb @@ -130,22 +130,55 @@ E before do Chef::Config.trusted_certs_dir = trusted_certs_dir - - expect(TCPSocket).to receive(:new).with("foo.example.com", 8443).and_return(tcp_socket) - expect(OpenSSL::SSL::SSLSocket).to receive(:new).with(tcp_socket, ssl_fetch.noverify_peer_ssl_context).and_return(ssl_socket) - expect(ssl_socket).to receive(:connect) - expect(ssl_socket).to receive(:peer_cert_chain).and_return([self_signed_crt]) end after do FileUtils.rm_rf(trusted_certs_dir) end - it "fetches the cert chain and writes the certs to the trusted_certs_dir" do - run - stored_cert_path = File.join(trusted_certs_dir, "example_local.crt") - expect(File).to exist(stored_cert_path) - expect(File.read(stored_cert_path)).to eq(File.read(self_signed_crt_path)) + context "when the TLS connection is successful" do + + before do + expect(TCPSocket).to receive(:new).with("foo.example.com", 8443).and_return(tcp_socket) + expect(OpenSSL::SSL::SSLSocket).to receive(:new).with(tcp_socket, ssl_fetch.noverify_peer_ssl_context).and_return(ssl_socket) + expect(ssl_socket).to receive(:connect) + expect(ssl_socket).to receive(:peer_cert_chain).and_return([self_signed_crt]) + end + + it "fetches the cert chain and writes the certs to the trusted_certs_dir" do + run + stored_cert_path = File.join(trusted_certs_dir, "example_local.crt") + expect(File).to exist(stored_cert_path) + expect(File.read(stored_cert_path)).to eq(File.read(self_signed_crt_path)) + end + + end + + context "when connecting to a non-SSL service (like HTTP)" do + + let(:name_args) { %w{http://foo.example.com} } + + let(:unknown_protocol_error) { OpenSSL::SSL::SSLError.new("SSL_connect returned=1 errno=0 state=SSLv2/v3 read server hello A: unknown protocol") } + + before do + expect(TCPSocket).to receive(:new).with("foo.example.com", 80).and_return(tcp_socket) + expect(OpenSSL::SSL::SSLSocket).to receive(:new).with(tcp_socket, ssl_fetch.noverify_peer_ssl_context).and_return(ssl_socket) + expect(ssl_socket).to receive(:connect).and_raise(unknown_protocol_error) + + expect(ssl_fetch).to receive(:exit).with(1) + end + + it "tells the user their URL is for a non-ssl service" do + expected_error_text = <<-ERROR_TEXT +ERROR: The service at the given URI (http://foo.example.com) does not accept SSL connections +ERROR: Perhaps you meant to connect to 'https://foo.example.com'? +ERROR_TEXT + + run + expect(stderr).to include(expected_error_text) + end + end + end end |