summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordanielsdeleo <dan@getchef.com>2014-12-10 12:54:34 -0800
committerdanielsdeleo <dan@getchef.com>2014-12-10 12:54:34 -0800
commitab6a1a70ce9390988a6541410a688742cad4fba8 (patch)
tree17351c23f31ced2ab28cc2bca3dfe0f02b1abc4d
parent1c2579ccbde1339c5dd1bd0612068aefbfc64b75 (diff)
downloadchef-ssl-fetch-non-ssl-error.tar.gz
Catch 'unknown protocol' errors in ssl fetch and explain themssl-fetch-non-ssl-error
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.rb13
-rw-r--r--spec/unit/knife/ssl_fetch_spec.rb53
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