Skip to content

Commit c9238ba

Browse files
authored
RUBY-1744 When handshake/auth fails, indicate which server authentication was attempted against and whether ssl was used (#1282)
1 parent 8f51fb1 commit c9238ba

File tree

10 files changed

+130
-10
lines changed

10 files changed

+130
-10
lines changed

lib/mongo/socket.rb

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ class Socket
3434
# Error message for timeouts on socket calls.
3535
#
3636
# @since 2.0.0
37+
# @deprecated
3738
TIMEOUT_ERROR = 'Socket request timed out'.freeze
3839

3940
# The pack directive for timeouts.
@@ -293,13 +294,17 @@ def set_socket_options(sock)
293294
def handle_errors
294295
begin
295296
yield
296-
rescue Errno::ETIMEDOUT
297-
raise Error::SocketTimeoutError, TIMEOUT_ERROR
297+
rescue Errno::ETIMEDOUT => e
298+
raise Error::SocketTimeoutError, "#{e.class}: #{e} (for #{address})"
298299
rescue IOError, SystemCallError => e
299-
raise Error::SocketError, "#{e.class}: #{e}"
300+
raise Error::SocketError, "#{e.class}: #{e} (for #{address})"
300301
rescue OpenSSL::SSL::SSLError => e
301-
raise Error::SocketError, "#{e.class}: #{e} (#{SSL_ERROR})"
302+
raise Error::SocketError, "#{e.class}: #{e} (for #{address}) (#{SSL_ERROR})"
302303
end
303304
end
305+
306+
def address
307+
raise NotImplementedError
308+
end
304309
end
305310
end

lib/mongo/socket/ssl.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,10 @@ def read_buffer_size
202202
# Capped at 16k due to https://linux.die.net/man/3/ssl_read
203203
16384
204204
end
205+
206+
def address
207+
"#{host}:#{port} (#{host_name}:#{port}, TLS)"
208+
end
205209
end
206210
end
207211
end

lib/mongo/socket/tcp.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,12 @@ def initialize(host, port, timeout, family, options = {})
6969
super(family)
7070
connect!
7171
end
72+
73+
private
74+
75+
def address
76+
"#{host}:#{port} (no TLS)"
77+
end
7278
end
7379
end
7480
end

lib/mongo/socket/unix.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,12 @@ def initialize(path, timeout, options = {})
4343
@socket = ::UNIXSocket.new(path)
4444
set_socket_options(@socket)
4545
end
46+
47+
private
48+
49+
def address
50+
path
51+
end
4652
end
4753
end
4854
end

spec/integration/auth_spec.rb

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,5 +118,43 @@
118118
end
119119
end
120120
end
121+
122+
context 'attempting to connect to a non-tls server with tls' do
123+
require_no_ssl
124+
125+
let(:options) { {ssl: true} }
126+
127+
it 'reports host, port and tls status' do
128+
begin
129+
connection.connect!
130+
rescue Mongo::Error::SocketError => exc
131+
end
132+
expect(exc).not_to be nil
133+
expect(exc.message).to include('OpenSSL::SSL::SSLError')
134+
expect(exc.message).to include(server.address.to_s)
135+
expect(exc.message).to include('TLS')
136+
expect(exc.message).not_to include('no TLS')
137+
end
138+
end
139+
140+
context 'attempting to connect to a tls server without tls' do
141+
require_ssl
142+
143+
let(:options) { {} }
144+
145+
it 'reports host, port and tls status' do
146+
begin
147+
connection.connect!
148+
rescue Mongo::Error::SocketError => exc
149+
end
150+
expect(exc).not_to be nil
151+
expect(exc.message).not_to include('OpenSSL::SSL::SSLError')
152+
addresses = Socket.getaddrinfo(server.address.host, nil)
153+
expect(addresses.any? do |address|
154+
exc.message.include?("#{address[2]}:#{server.address.port}")
155+
end).to be true
156+
expect(exc.message).to include('no TLS')
157+
end
158+
end
121159
end
122160
end

spec/mongo/socket/ssl_spec.rb

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,13 @@
4949
OpenSSL::PKey.read(key_string)
5050
end
5151

52+
describe '#address' do
53+
it 'returns the address and tls indicator' do
54+
addr = socket.instance_variable_get(:@tcp_socket).remote_address
55+
expect(socket.send(:address)).to eq("#{addr.ip_address}:#{addr.ip_port} (#{default_address}, TLS)")
56+
end
57+
end
58+
5259
describe '#connect!' do
5360

5461
context 'when a certificate is provided' do
@@ -563,9 +570,13 @@
563570

564571
let(:socket_content) { "" }
565572

573+
let(:remote_address) { socket.instance_variable_get(:@tcp_socket).remote_address }
574+
let(:address_str) { "#{remote_address.ip_address}:#{remote_address.ip_port} (#{default_address}, TLS)" }
575+
566576
it 'should raise EOFError' do
567-
expect { socket.readbyte }
568-
.to raise_error(Mongo::Error::SocketError).with_message("EOFError: EOFError")
577+
expect do
578+
socket.readbyte
579+
end.to raise_error(Mongo::Error::SocketError).with_message("EOFError: EOFError (for #{address_str})")
569580
end
570581
end
571582
end

spec/mongo/socket/tcp_spec.rb

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
require 'spec_helper'
2+
3+
describe Mongo::Socket::TCP do
4+
require_no_ssl
5+
6+
let(:address) { default_address }
7+
8+
let!(:resolver) do
9+
address.send(:create_resolver, {})
10+
end
11+
12+
let(:socket) do
13+
resolver.socket(5, {})
14+
end
15+
16+
describe '#address' do
17+
it 'returns the address and tls indicator' do
18+
addr = socket.send(:socket).remote_address
19+
expect(socket.send(:address)).to eq("#{addr.ip_address}:#{addr.ip_port} (no TLS)")
20+
end
21+
end
22+
end

spec/mongo/socket/unix_spec.rb

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,16 @@
22

33
describe Mongo::Socket::Unix do
44

5+
let(:path) { "/tmp/mongodb-#{SpecConfig.instance.any_port}.sock" }
6+
57
let(:socket) do
6-
described_class.new("/tmp/mongodb-#{SpecConfig.instance.any_port}.sock", 5)
8+
described_class.new(path, 5)
9+
end
10+
11+
describe '#address' do
12+
it 'returns the path' do
13+
expect(socket.send(:address)).to eq(path)
14+
end
715
end
816

917
describe '#connect!' do

spec/mongo/socket_spec.rb

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,19 @@
66
described_class.new(Socket::PF_INET)
77
end
88

9+
describe '#address' do
10+
it 'raises NotImplementedError' do
11+
expect do
12+
socket.send(:address)
13+
end.to raise_error(NotImplementedError)
14+
end
15+
end
16+
917
describe '#handle_errors' do
18+
before do
19+
expect(socket).to receive(:address).and_return('fake-address')
20+
end
21+
1022
it 'maps timeout exception' do
1123
expect do
1224
socket.send(:handle_errors) do
@@ -20,23 +32,23 @@
2032
socket.send(:handle_errors) do
2133
raise SystemCallError.new('Test error', Errno::ENFILE::Errno)
2234
end
23-
end.to raise_error(Mongo::Error::SocketError, 'Errno::ENFILE: Too many open files in system - Test error')
35+
end.to raise_error(Mongo::Error::SocketError, 'Errno::ENFILE: Too many open files in system - Test error (for fake-address)')
2436
end
2537

2638
it 'maps IOError and preserves message' do
2739
expect do
2840
socket.send(:handle_errors) do
2941
raise IOError.new('Test error')
3042
end
31-
end.to raise_error(Mongo::Error::SocketError, 'IOError: Test error')
43+
end.to raise_error(Mongo::Error::SocketError, 'IOError: Test error (for fake-address)')
3244
end
3345

3446
it 'maps SSLError and preserves message' do
3547
expect do
3648
socket.send(:handle_errors) do
3749
raise OpenSSL::SSL::SSLError.new('Test error')
3850
end
39-
end.to raise_error(Mongo::Error::SocketError, 'OpenSSL::SSL::SSLError: Test error (MongoDB may not be configured with SSL support)')
51+
end.to raise_error(Mongo::Error::SocketError, 'OpenSSL::SSL::SSLError: Test error (for fake-address) (MongoDB may not be configured with SSL support)')
4052
end
4153
end
4254
end

spec/support/constraints.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,14 @@ def require_ssl
8080
end
8181
end
8282

83+
def require_no_ssl
84+
before do
85+
if SpecConfig.instance.ssl?
86+
skip "SSL enabled"
87+
end
88+
end
89+
end
90+
8391
def require_local_tls
8492
before do
8593
unless SpecConfig.instance.ssl? && !SpecConfig.instance.ci?

0 commit comments

Comments
 (0)