RUBY-424 Authenticating with only secondary fails

Authentication command now prefers to use primary node but will fall
back on secondary if no primary is available
This commit is contained in:
Tyler Brock 2012-03-15 13:50:02 -04:00
parent 7fd0b8dfce
commit ec86275b60
4 changed files with 62 additions and 9 deletions

View File

@ -480,6 +480,12 @@ module Mongo
@max_bson_size
end
# Prefer primary pool but fall back to secondary
def checkout_best
connect unless connected?
@primary_pool.checkout
end
# Checkout a socket for reading (i.e., a secondary node).
# Note: this is overridden in ReplSetConnection.
def checkout_reader
@ -513,6 +519,19 @@ module Mongo
end
end
# Excecutes block with the best available socket
def best_available_socket
socket = nil
begin
socket = checkout_best
yield socket
ensure
if socket
socket.pool.checkin(socket)
end
end
end
protected
def valid_opts

View File

@ -111,10 +111,13 @@ module Mongo
if !save_auth
raise MongoArgumentError, "If using connection pooling, :save_auth must be set to true."
end
@connection.authenticate_pools
end
issue_authentication(username, password, save_auth)
@connection.best_available_socket do |socket|
issue_authentication(username, password, save_auth, :socket => socket)
end
@connection.authenticate_pools
end
def issue_authentication(username, password, save_auth=true, opts={})

View File

@ -287,14 +287,18 @@ module Mongo
end
def authenticate_pools
primary_pool.authenticate_existing
if primary_pool
primary_pool.authenticate_existing
end
secondary_pools.each do |pool|
pool.authenticate_existing
end
end
def logout_pools(db)
primary_pool.logout_existing(db)
if primary_pool
primary_pool.logout_existing(db)
end
secondary_pools.each do |pool|
pool.logout_existing(db)
end
@ -323,6 +327,19 @@ module Mongo
raise ConnectionFailure.new("Could not checkout a socket.")
end
end
# Checkout best available socket by trying primary
# pool first and then falling back to secondary.
def checkout_best
checkout do
socket = get_socket_from_pool(:primary)
if !socket
connect
socket = get_socket_from_pool(:secondary)
end
socket
end
end
# Checkout a socket for reading (i.e., a secondary node).
# Note that @read_pool might point to the primary pool

View File

@ -1,21 +1,22 @@
$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
require './test/test_helper'
require './test/tools/auth_repl_set_manager'
require './test/replica_sets/rs_test_helper'
class AuthTest < Test::Unit::TestCase
include Mongo
def setup
@manager = AuthReplSetManager.new(:start_port => 40000)
@manager.start_set
@rs = AuthReplSetManager.new(:start_port => 40000)
@rs.start_set
end
def teardown
@manager.cleanup_set
#@rs.cleanup_set
end
def test_repl_set_auth
@conn = ReplSetConnection.new(build_seeds(3), :name => @manager.name)
@conn = ReplSetConnection.new(build_seeds(3), :name => @rs.name)
# Add an admin user
@conn['admin'].add_user("me", "secret")
@ -51,7 +52,20 @@ class AuthTest < Test::Unit::TestCase
end
# But not when authenticated
@slave1['admin'].authenticate("me", "secret")
assert @slave1['admin'].authenticate("me", "secret")
assert @slave1['foo']['stuff'].find_one
# Same should apply when using :secondary_only
@second_only = ReplSetConnection.new(build_seeds(3),
:require_primary => false, :read => :secondary_only)
# Find should fail
assert_raise_error Mongo::OperationFailure, "unauthorized" do
@second_only['foo']['stuff'].find_one
end
# But not when authenticated
assert @second_only['admin'].authenticate("me", "secret")
assert @second_only['foo']['stuff'].find_one
end
end