Permalink
Browse files

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
  • Loading branch information...
TylerBrock committed Mar 15, 2012
1 parent 7fd0b8d commit ec86275b6060db33a03b57d3b0926c9ffff62c0a
Showing with 62 additions and 9 deletions.
  1. +19 −0 lib/mongo/connection.rb
  2. +5 −2 lib/mongo/db.rb
  3. +19 −2 lib/mongo/repl_set_connection.rb
  4. +19 −5 test/auxillary/repl_set_auth_test.rb
View
@@ -480,6 +480,12 @@ def max_bson_size
@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 @@ def checkin(socket)
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
@@ -111,10 +111,13 @@ def authenticate(username, password, save_auth=true)
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={})
@@ -287,14 +287,18 @@ def slave_ok?
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 @@ def checkout(&block)
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
@@ -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 @@ def test_repl_set_auth
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

0 comments on commit ec86275

Please sign in to comment.