RUBY-316 initial SSL support
This commit is contained in:
parent
8db62d2cbf
commit
f00c0dfcf0
|
@ -59,6 +59,7 @@ require 'mongo/util/core_ext'
|
||||||
require 'mongo/util/pool'
|
require 'mongo/util/pool'
|
||||||
require 'mongo/util/pool_manager'
|
require 'mongo/util/pool_manager'
|
||||||
require 'mongo/util/server_version'
|
require 'mongo/util/server_version'
|
||||||
|
require 'mongo/util/ssl_socket'
|
||||||
require 'mongo/util/uri_parser'
|
require 'mongo/util/uri_parser'
|
||||||
|
|
||||||
require 'mongo/collection'
|
require 'mongo/collection'
|
||||||
|
|
|
@ -36,7 +36,7 @@ module Mongo
|
||||||
RESPONSE_HEADER_SIZE = 20
|
RESPONSE_HEADER_SIZE = 20
|
||||||
|
|
||||||
attr_reader :logger, :size, :auths, :primary, :safe, :host_to_try,
|
attr_reader :logger, :size, :auths, :primary, :safe, :host_to_try,
|
||||||
:pool_size, :connect_timeout, :primary_pool
|
:pool_size, :connect_timeout, :primary_pool, :socket_class
|
||||||
|
|
||||||
# Counter for generating unique request ids.
|
# Counter for generating unique request ids.
|
||||||
@@current_request_id = 0
|
@@current_request_id = 0
|
||||||
|
@ -73,6 +73,7 @@ module Mongo
|
||||||
# Disabled by default.
|
# Disabled by default.
|
||||||
# @option opts [Float] :connect_timeout (nil) The number of seconds to wait before timing out a
|
# @option opts [Float] :connect_timeout (nil) The number of seconds to wait before timing out a
|
||||||
# connection attempt.
|
# connection attempt.
|
||||||
|
# @option opts [Boolean] :ssl (false) If true, create the connection to the server using SSL.
|
||||||
#
|
#
|
||||||
# @example localhost, 27017
|
# @example localhost, 27017
|
||||||
# Connection.new
|
# Connection.new
|
||||||
|
@ -636,6 +637,14 @@ module Mongo
|
||||||
# Default maximum BSON object size
|
# Default maximum BSON object size
|
||||||
@max_bson_size = Mongo::DEFAULT_MAX_BSON_SIZE
|
@max_bson_size = Mongo::DEFAULT_MAX_BSON_SIZE
|
||||||
|
|
||||||
|
# Determine whether to use SSL.
|
||||||
|
@ssl = opts.fetch(:ssl, false)
|
||||||
|
if @ssl
|
||||||
|
@socket_class = Mongo::SSLSocket
|
||||||
|
else
|
||||||
|
@socket_class = ::TCPSocket
|
||||||
|
end
|
||||||
|
|
||||||
# Authentication objects
|
# Authentication objects
|
||||||
@auths = opts.fetch(:auths, [])
|
@auths = opts.fetch(:auths, [])
|
||||||
|
|
||||||
|
@ -729,11 +738,11 @@ module Mongo
|
||||||
|
|
||||||
if @connect_timeout
|
if @connect_timeout
|
||||||
Mongo::TimeoutHandler.timeout(@connect_timeout, OperationTimeout) do
|
Mongo::TimeoutHandler.timeout(@connect_timeout, OperationTimeout) do
|
||||||
socket = TCPSocket.new(host, port)
|
socket = @socket_class.new(host, port)
|
||||||
socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
|
socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
socket = TCPSocket.new(host, port)
|
socket = @socket_class.new(host, port)
|
||||||
socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
|
socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -31,10 +31,10 @@ module Mongo
|
||||||
socket = nil
|
socket = nil
|
||||||
if self.connection.connect_timeout
|
if self.connection.connect_timeout
|
||||||
Mongo::TimeoutHandler.timeout(self.connection.connect_timeout, OperationTimeout) do
|
Mongo::TimeoutHandler.timeout(self.connection.connect_timeout, OperationTimeout) do
|
||||||
socket = TCPSocket.new(self.host, self.port)
|
socket = self.connection.socket_class.new(self.host, self.port)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
socket = TCPSocket.new(self.host, self.port)
|
socket = self.connection.socket_class.new(self.host, self.port)
|
||||||
end
|
end
|
||||||
|
|
||||||
if socket.nil?
|
if socket.nil?
|
||||||
|
|
|
@ -110,7 +110,7 @@ module Mongo
|
||||||
# therefore, it runs within a mutex.
|
# therefore, it runs within a mutex.
|
||||||
def checkout_new_socket
|
def checkout_new_socket
|
||||||
begin
|
begin
|
||||||
socket = TCPSocket.new(@host, @port)
|
socket = self.connection.socket_class.new(@host, @port)
|
||||||
socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
|
socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
|
||||||
rescue => ex
|
rescue => ex
|
||||||
socket.close if socket
|
socket.close if socket
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
require 'openssl'
|
||||||
|
|
||||||
|
module Mongo
|
||||||
|
|
||||||
|
# A basic wrapper over Ruby's SSLSocket that initiates
|
||||||
|
# a TCP connection over SSL and then provides an basic interface
|
||||||
|
# mirroring Ruby's TCPSocket, vis., TCPSocket#send and TCPSocket#read.
|
||||||
|
class SSLSocket
|
||||||
|
|
||||||
|
def initialize(host, port)
|
||||||
|
@socket = ::TCPSocket.new(host, port)
|
||||||
|
@ssl = OpenSSL::SSL::SSLSocket.new(@socket)
|
||||||
|
@ssl.sync_close = true
|
||||||
|
@ssl.connect
|
||||||
|
end
|
||||||
|
|
||||||
|
def setsockopt(key, value, n)
|
||||||
|
@socket.setsockopt(key, value, n)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Write to the SSL socket.
|
||||||
|
#
|
||||||
|
# @param buffer a buffer to send.
|
||||||
|
# @param flags socket flags. Because Ruby's SSL
|
||||||
|
def send(buffer, flags=0)
|
||||||
|
@ssl.syswrite(buffer)
|
||||||
|
end
|
||||||
|
|
||||||
|
def read(length, buffer)
|
||||||
|
@ssl.sysread(length, buffer)
|
||||||
|
end
|
||||||
|
|
||||||
|
def close
|
||||||
|
@ssl.close
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
|
@ -7,8 +7,10 @@ class NodeTest < Test::Unit::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
should "refuse to connect to node without 'hosts' key" do
|
should "refuse to connect to node without 'hosts' key" do
|
||||||
|
tcp = mock()
|
||||||
node = Node.new(@connection, ['localhost', 27017])
|
node = Node.new(@connection, ['localhost', 27017])
|
||||||
TCPSocket.stubs(:new).returns(new_mock_socket)
|
tcp.stubs(:new).returns(new_mock_socket)
|
||||||
|
@connection.stubs(:socket_class).returns(tcp)
|
||||||
|
|
||||||
admin_db = new_mock_db
|
admin_db = new_mock_db
|
||||||
admin_db.stubs(:command).returns({'ok' => 1, 'ismaster' => 1})
|
admin_db.stubs(:command).returns({'ok' => 1, 'ismaster' => 1})
|
||||||
|
@ -17,7 +19,7 @@ class NodeTest < Test::Unit::TestCase
|
||||||
@connection.expects(:log)
|
@connection.expects(:log)
|
||||||
|
|
||||||
assert node.connect
|
assert node.connect
|
||||||
assert node.set_config
|
node.set_config
|
||||||
end
|
end
|
||||||
|
|
||||||
should "load a node from an array" do
|
should "load a node from an array" do
|
||||||
|
|
Loading…
Reference in New Issue