added authentication support for copy_database
This commit is contained in:
parent
38d6401d1a
commit
9dd1a5c2e3
|
@ -48,6 +48,7 @@ require 'mongo/types/regexp_of_holding'
|
|||
require 'mongo/types/min_max_keys'
|
||||
|
||||
require 'mongo/util/support'
|
||||
require 'mongo/util/core_ext'
|
||||
require 'mongo/util/conversions'
|
||||
require 'mongo/util/server_version'
|
||||
require 'mongo/util/bson_ruby'
|
||||
|
|
|
@ -276,19 +276,33 @@ module Mongo
|
|||
self[name].command(:dropDatabase => 1)
|
||||
end
|
||||
|
||||
# Copy the database +from+ on the local server to +to+ on the specified +host+.
|
||||
# +host+ defaults to 'localhost' if no value is provided.
|
||||
# Copy the database +from+ to +to+ on localhost. The +from+ database is
|
||||
# assumed to be on localhost, but an alternate host can be specified.
|
||||
#
|
||||
# @param [String] from name of the database to copy from.
|
||||
# @param [String] to name of the database to copy to.
|
||||
# @param [String] from_host host of the 'from' database.
|
||||
def copy_database(from, to, from_host="localhost")
|
||||
# @param [String] username username for authentication against from_db (>=1.3.x).
|
||||
# @param [String] password password for authentication against from_db (>=1.3.x).
|
||||
def copy_database(from, to, from_host="localhost", username=nil, password=nil)
|
||||
oh = OrderedHash.new
|
||||
oh[:copydb] = 1
|
||||
oh[:fromhost] = from_host
|
||||
oh[:fromdb] = from
|
||||
oh[:todb] = to
|
||||
self["admin"].command(oh, false, true)
|
||||
if username || password
|
||||
unless username && password
|
||||
raise MongoArgumentError, "Both username and password must be supplied for authentication."
|
||||
end
|
||||
nonce_cmd = OrderedHash.new
|
||||
nonce_cmd[:copydbgetnonce] = 1
|
||||
nonce_cmd[:fromhost] = from_host
|
||||
result = self["admin"].command(nonce_cmd, true, true)
|
||||
oh[:nonce] = result["nonce"]
|
||||
oh[:username] = username
|
||||
oh[:key] = Mongo::Support.auth_key(username, password, oh[:nonce])
|
||||
end
|
||||
self["admin"].command(oh, true, true)
|
||||
end
|
||||
|
||||
# Increment and return the next available request id.
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
require 'socket'
|
||||
require 'timeout'
|
||||
require 'digest/md5'
|
||||
require 'thread'
|
||||
|
||||
module Mongo
|
||||
|
@ -65,7 +64,7 @@ module Mongo
|
|||
#
|
||||
# @core databases constructor_details
|
||||
def initialize(db_name, connection, options={})
|
||||
@name = validate_db_name(db_name)
|
||||
@name = Mongo::Support.validate_db_name(db_name)
|
||||
@connection = connection
|
||||
@strict = options[:strict]
|
||||
@pk_factory = options[:pk]
|
||||
|
@ -94,7 +93,7 @@ module Mongo
|
|||
auth['authenticate'] = 1
|
||||
auth['user'] = username
|
||||
auth['nonce'] = nonce
|
||||
auth['key'] = Digest::MD5.hexdigest("#{nonce}#{username}#{hash_password(username, password)}")
|
||||
auth['key'] = Mongo::Support.auth_key(username, password, nonce)
|
||||
if ok?(command(auth))
|
||||
if save_auth
|
||||
@connection.add_auth(@name, username, password)
|
||||
|
@ -115,7 +114,7 @@ module Mongo
|
|||
def add_user(username, password)
|
||||
users = self[SYSTEM_USER_COLLECTION]
|
||||
user = users.find_one({:user => username}) || {:user => username}
|
||||
user['pwd'] = hash_password(username, password)
|
||||
user['pwd'] = Mongo::Support.hash_password(username, password)
|
||||
users.save(user)
|
||||
return user
|
||||
end
|
||||
|
@ -444,7 +443,7 @@ module Mongo
|
|||
:limit => -1, :selector => selector, :socket => sock).next_document
|
||||
|
||||
if check_response && !ok?(result)
|
||||
raise OperationFailure, "Database command '#{selector.keys.first}' failed."
|
||||
raise OperationFailure, "Database command '#{selector.keys.first}' failed: #{result.inspect}"
|
||||
else
|
||||
result
|
||||
end
|
||||
|
@ -546,26 +545,8 @@ module Mongo
|
|||
|
||||
private
|
||||
|
||||
def hash_password(username, plaintext)
|
||||
Digest::MD5.hexdigest("#{username}:mongo:#{plaintext}")
|
||||
end
|
||||
|
||||
def system_command_collection
|
||||
Collection.new(self, SYSTEM_COMMAND_COLLECTION)
|
||||
end
|
||||
|
||||
def validate_db_name(db_name)
|
||||
unless [String, Symbol].include?(db_name.class)
|
||||
raise TypeError, "db_name must be a string or symbol"
|
||||
end
|
||||
|
||||
[" ", ".", "$", "/", "\\"].each do |invalid_char|
|
||||
if db_name.include? invalid_char
|
||||
raise InvalidName, "database names cannot contain the character '#{invalid_char}'"
|
||||
end
|
||||
end
|
||||
raise InvalidName, "database name cannot be the empty string" if db_name.empty?
|
||||
db_name
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
# --
|
||||
# Copyright (C) 2008-2010 10gen Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# ++
|
||||
|
||||
#:nodoc:
|
||||
class Object
|
||||
|
||||
#:nodoc:
|
||||
def returning(value)
|
||||
yield value
|
||||
value
|
||||
end
|
||||
|
||||
end
|
|
@ -14,13 +14,46 @@
|
|||
# limitations under the License.
|
||||
# ++
|
||||
|
||||
#:nodoc:
|
||||
class Object
|
||||
require 'digest/md5'
|
||||
|
||||
#:nodoc:
|
||||
def returning(value)
|
||||
yield value
|
||||
value
|
||||
module Mongo
|
||||
module Support
|
||||
extend self
|
||||
|
||||
# Generate an MD5 for authentication.
|
||||
#
|
||||
# @param [String] username
|
||||
# @param [String] password
|
||||
# @param [String] nonce
|
||||
#
|
||||
# @return [String] a key for db authentication.
|
||||
def auth_key(username, password, nonce)
|
||||
Digest::MD5.hexdigest("#{nonce}#{username}#{hash_password(username, password)}")
|
||||
end
|
||||
|
||||
# Return a hashed password for auth.
|
||||
#
|
||||
# @param [String] username
|
||||
# @param [String] plaintext
|
||||
#
|
||||
# @return [String]
|
||||
def hash_password(username, plaintext)
|
||||
Digest::MD5.hexdigest("#{username}:mongo:#{plaintext}")
|
||||
end
|
||||
|
||||
|
||||
def validate_db_name(db_name)
|
||||
unless [String, Symbol].include?(db_name.class)
|
||||
raise TypeError, "db_name must be a string or symbol"
|
||||
end
|
||||
|
||||
[" ", ".", "$", "/", "\\"].each do |invalid_char|
|
||||
if db_name.include? invalid_char
|
||||
raise InvalidName, "database names cannot contain the character '#{invalid_char}'"
|
||||
end
|
||||
end
|
||||
raise InvalidName, "database name cannot be the empty string" if db_name.empty?
|
||||
db_name
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -58,6 +58,23 @@ class TestConnection < Test::Unit::TestCase
|
|||
old_object = @mongo.db('old').collection('copy-test').find.next_document
|
||||
new_object = @mongo.db('new').collection('copy-test').find.next_document
|
||||
assert_equal old_object, new_object
|
||||
@mongo.drop_database('old')
|
||||
@mongo.drop_database('new')
|
||||
end
|
||||
|
||||
def test_copy_database_with_auth
|
||||
@mongo.db('old').collection('copy-test').insert('a' => 1)
|
||||
@mongo.db('old').add_user('bob', 'secret')
|
||||
|
||||
assert_raise Mongo::OperationFailure do
|
||||
@mongo.copy_database('old', 'new', 'localhost', 'bob', 'badpassword')
|
||||
end
|
||||
|
||||
result = @mongo.copy_database('old', 'new', 'localhost', 'bob', 'secret')
|
||||
assert result['ok'].to_i == 1
|
||||
|
||||
@mongo.drop_database('old')
|
||||
@mongo.drop_database('new')
|
||||
end
|
||||
|
||||
def test_database_names
|
||||
|
|
Loading…
Reference in New Issue