mongo 1.11.1 → 1.12.0.rc0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/VERSION +1 -1
- data/lib/mongo/collection.rb +8 -3
- data/lib/mongo/collection_writer.rb +1 -1
- data/lib/mongo/connection/socket/unix_socket.rb +1 -1
- data/lib/mongo/cursor.rb +8 -1
- data/lib/mongo/db.rb +61 -33
- data/lib/mongo/exception.rb +57 -0
- data/lib/mongo/functional.rb +1 -0
- data/lib/mongo/functional/authentication.rb +138 -11
- data/lib/mongo/functional/read_preference.rb +31 -22
- data/lib/mongo/functional/scram.rb +555 -0
- data/lib/mongo/functional/uri_parser.rb +107 -79
- data/lib/mongo/mongo_client.rb +19 -24
- data/lib/mongo/mongo_replica_set_client.rb +2 -1
- data/test/functional/authentication_test.rb +3 -0
- data/test/functional/client_test.rb +33 -0
- data/test/functional/collection_test.rb +29 -19
- data/test/functional/db_api_test.rb +16 -1
- data/test/functional/pool_test.rb +7 -6
- data/test/functional/uri_test.rb +111 -7
- data/test/helpers/test_unit.rb +17 -3
- data/test/replica_set/client_test.rb +31 -0
- data/test/replica_set/insert_test.rb +49 -32
- data/test/replica_set/pinning_test.rb +50 -0
- data/test/replica_set/query_test.rb +1 -1
- data/test/replica_set/replication_ack_test.rb +3 -3
- data/test/shared/authentication/basic_auth_shared.rb +14 -1
- data/test/shared/authentication/gssapi_shared.rb +13 -8
- data/test/shared/authentication/scram_shared.rb +92 -0
- data/test/tools/mongo_config.rb +18 -6
- data/test/unit/client_test.rb +40 -6
- data/test/unit/connection_test.rb +15 -5
- data/test/unit/db_test.rb +1 -1
- data/test/unit/read_pref_test.rb +291 -0
- metadata +9 -6
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0c376366d59154151291d12a0a859a6db8850416
|
4
|
+
data.tar.gz: 7d92d814592073a3f2548fea9b2960e241c98502
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dc0c717e7741c0871d80af3b6f65be1bd8908a2e0364c6bf17106056f5d71ea4677f410a4cacf0a6ec85181486a2e3eb5392a1b09472c0d728ac9c3dcaecd027
|
7
|
+
data.tar.gz: fd7c88744f849a3cdec1a1e514a2028d4391615028dceb3c48edb0fbe5b6f87a1bceae1745cbc96ad2c0f96f0380897d6f1a9668d4a620adb9d52b0b32c67fe5
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data.tar.gz.sig
CHANGED
Binary file
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.12.0.rc0
|
data/lib/mongo/collection.rb
CHANGED
@@ -717,11 +717,13 @@ module Mongo
|
|
717
717
|
|
718
718
|
if result.key?('cursor')
|
719
719
|
cursor_info = result['cursor']
|
720
|
+
pinned_pool = @connection.pinned_pool
|
721
|
+
pinned_pool = pinned_pool[:pool] if pinned_pool.respond_to?(:keys)
|
720
722
|
|
721
723
|
seed = {
|
722
724
|
:cursor_id => cursor_info['id'],
|
723
725
|
:first_batch => cursor_info['firstBatch'],
|
724
|
-
:pool =>
|
726
|
+
:pool => pinned_pool
|
725
727
|
}
|
726
728
|
|
727
729
|
return Cursor.new(self, seed.merge!(opts))
|
@@ -887,10 +889,13 @@ module Mongo
|
|
887
889
|
result = @db.command(cmd, command_options(opts))
|
888
890
|
|
889
891
|
result['cursors'].collect do |cursor_info|
|
892
|
+
pinned_pool = @connection.pinned_pool
|
893
|
+
pinned_pool = pinned_pool[:pool] if pinned_pool.respond_to?(:keys)
|
894
|
+
|
890
895
|
seed = {
|
891
896
|
:cursor_id => cursor_info['cursor']['id'],
|
892
897
|
:first_batch => cursor_info['cursor']['firstBatch'],
|
893
|
-
:pool =>
|
898
|
+
:pool => pinned_pool
|
894
899
|
}
|
895
900
|
Cursor.new(self, seed.merge!(opts))
|
896
901
|
end
|
@@ -1024,7 +1029,7 @@ module Mongo
|
|
1024
1029
|
#
|
1025
1030
|
# @return [Hash] options that apply to this collection.
|
1026
1031
|
def options
|
1027
|
-
@db.collections_info(@name).
|
1032
|
+
@db.collections_info(@name).first['options']
|
1028
1033
|
end
|
1029
1034
|
|
1030
1035
|
# Return stats on the collection. Uses MongoDB's collstats command.
|
@@ -55,7 +55,7 @@ module Mongo
|
|
55
55
|
@max_write_batch_size = @collection.db.connection.max_write_batch_size
|
56
56
|
docs = documents.dup
|
57
57
|
catch(:error) do
|
58
|
-
until docs.empty? || (!errors.empty? && !collect_on_error) # process documents a batch at a time
|
58
|
+
until docs.empty? || (!errors.empty? && !collect_on_error && !continue_on_error) # process documents a batch at a time
|
59
59
|
batch_docs = []
|
60
60
|
batch_message_initialize(message, op_type, continue_on_error, write_concern)
|
61
61
|
while !docs.empty? && batch_docs.size < @max_write_batch_size
|
data/lib/mongo/cursor.rb
CHANGED
@@ -564,9 +564,11 @@ module Mongo
|
|
564
564
|
ensure
|
565
565
|
socket.checkin unless @socket || socket.nil?
|
566
566
|
end
|
567
|
-
|
567
|
+
|
568
|
+
if pin_pool?(results.first)
|
568
569
|
@connection.pin_pool(socket.pool, read_preference)
|
569
570
|
end
|
571
|
+
|
570
572
|
@returned += @n_received
|
571
573
|
@cache += results
|
572
574
|
@query_run = true
|
@@ -728,5 +730,10 @@ module Mongo
|
|
728
730
|
end
|
729
731
|
indexes.join("_")
|
730
732
|
end
|
733
|
+
|
734
|
+
def pin_pool?(response)
|
735
|
+
( response && (response['cursor'] || response['cursors']) ) ||
|
736
|
+
( !@socket && !@command )
|
737
|
+
end
|
731
738
|
end
|
732
739
|
end
|
data/lib/mongo/db.rb
CHANGED
@@ -217,27 +217,25 @@ module Mongo
|
|
217
217
|
#
|
218
218
|
# @return [Hash] an object representing the user.
|
219
219
|
def add_user(username, password=nil, read_only=false, opts={})
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
raise ex
|
240
|
-
end
|
220
|
+
user_info = command(:usersInfo => username)
|
221
|
+
if user_info.key?('users') && !user_info['users'].empty?
|
222
|
+
create_or_update_user(:updateUser, username, password, read_only, opts)
|
223
|
+
else
|
224
|
+
create_or_update_user(:createUser, username, password, read_only, opts)
|
225
|
+
end
|
226
|
+
# MongoDB >= 2.5.3 requires the use of commands to manage users.
|
227
|
+
# "Command not found" error didn't return an error code (59) before
|
228
|
+
# MongoDB 2.4.7 so we assume that a nil error code means the usersInfo
|
229
|
+
# command doesn't exist and we should fall back to the legacy add user code.
|
230
|
+
rescue OperationFailure => ex
|
231
|
+
if Mongo::ErrorCode::COMMAND_NOT_FOUND_CODES.include?(ex.error_code)
|
232
|
+
legacy_add_user(username, password, read_only, opts)
|
233
|
+
elsif ex.error_code == Mongo::ErrorCode::UNAUTHORIZED
|
234
|
+
# In MongoDB > 2.7 the localhost exception was narrowed, and the usersInfo
|
235
|
+
# command is no longer allowed. In this case, add the first user.
|
236
|
+
create_or_update_user(:createUser, username, password, read_only, opts)
|
237
|
+
else
|
238
|
+
raise ex
|
241
239
|
end
|
242
240
|
end
|
243
241
|
|
@@ -261,9 +259,14 @@ module Mongo
|
|
261
259
|
#
|
262
260
|
# @return [Array]
|
263
261
|
def collection_names
|
264
|
-
|
265
|
-
|
266
|
-
|
262
|
+
if @client.wire_version_feature?(Mongo::MongoClient::MONGODB_2_8)
|
263
|
+
names = collections_info.collect { |doc| doc['name'] || '' }
|
264
|
+
names.delete_if do |name|
|
265
|
+
name.index('$')
|
266
|
+
end
|
267
|
+
else
|
268
|
+
legacy_collection_names
|
269
|
+
end
|
267
270
|
end
|
268
271
|
|
269
272
|
# Get an array of Collection instances, one for each collection in this database.
|
@@ -281,11 +284,15 @@ module Mongo
|
|
281
284
|
#
|
282
285
|
# @param [String] coll_name return info for the specified collection only.
|
283
286
|
#
|
284
|
-
# @return [
|
287
|
+
# @return [Array] List of collection info.
|
285
288
|
def collections_info(coll_name=nil)
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
+
if @client.wire_version_feature?(Mongo::MongoClient::MONGODB_2_8)
|
290
|
+
cmd = BSON::OrderedHash[:listCollections, 1]
|
291
|
+
cmd.merge!(:filter => { :name => coll_name }) if coll_name
|
292
|
+
self.command(cmd)['collections']
|
293
|
+
else
|
294
|
+
legacy_collections_info(coll_name).to_a
|
295
|
+
end
|
289
296
|
end
|
290
297
|
|
291
298
|
# Create a collection.
|
@@ -482,12 +489,14 @@ module Mongo
|
|
482
489
|
# @return [Hash] keys are index names and the values are lists of [key, type] pairs
|
483
490
|
# defining the index.
|
484
491
|
def index_information(collection_name)
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
492
|
+
if @client.wire_version_feature?(Mongo::MongoClient::MONGODB_2_8)
|
493
|
+
result = self.command(:listIndexes => collection_name)['indexes']
|
494
|
+
else
|
495
|
+
result = legacy_list_indexes(collection_name)
|
496
|
+
end
|
497
|
+
result.reduce({}) do |info, index|
|
498
|
+
info.merge!(index['name'] => index)
|
489
499
|
end
|
490
|
-
info
|
491
500
|
end
|
492
501
|
|
493
502
|
# Return stats on this database. Uses MongoDB's dbstats command.
|
@@ -736,5 +745,24 @@ module Mongo
|
|
736
745
|
end
|
737
746
|
user
|
738
747
|
end
|
748
|
+
|
749
|
+
def legacy_list_indexes(collection_name)
|
750
|
+
sel = {:ns => full_collection_name(collection_name)}
|
751
|
+
Cursor.new(Collection.new(SYSTEM_INDEX_COLLECTION, self), :selector => sel)
|
752
|
+
end
|
753
|
+
|
754
|
+
def legacy_collections_info(coll_name=nil)
|
755
|
+
selector = {}
|
756
|
+
selector[:name] = full_collection_name(coll_name) if coll_name
|
757
|
+
Cursor.new(Collection.new(SYSTEM_NAMESPACE_COLLECTION, self), :selector => selector)
|
758
|
+
end
|
759
|
+
|
760
|
+
def legacy_collection_names
|
761
|
+
names = legacy_collections_info.collect { |doc| doc['name'] || '' }
|
762
|
+
names = names.delete_if do |name|
|
763
|
+
name.index(@name).nil? || name.index('$')
|
764
|
+
end
|
765
|
+
names.map {|name| name.sub(@name + '.', '')}
|
766
|
+
end
|
739
767
|
end
|
740
768
|
end
|
data/lib/mongo/exception.rb
CHANGED
@@ -85,4 +85,61 @@ module Mongo
|
|
85
85
|
|
86
86
|
# Raised for bulk write errors.
|
87
87
|
class BulkWriteError < OperationFailure; end
|
88
|
+
|
89
|
+
# This exception is raised when the server nonce returned does not
|
90
|
+
# match the client nonce sent to it.
|
91
|
+
#
|
92
|
+
# @since 1.12.0
|
93
|
+
class InvalidNonce < OperationFailure
|
94
|
+
|
95
|
+
# @return [ String ] nonce The client nonce.
|
96
|
+
attr_reader :nonce
|
97
|
+
|
98
|
+
# @return [ String ] rnonce The server nonce.
|
99
|
+
attr_reader :rnonce
|
100
|
+
|
101
|
+
# Instantiate the new exception.
|
102
|
+
#
|
103
|
+
# @example Create the exception.
|
104
|
+
# InvalidNonce.new(nonce, rnonce)
|
105
|
+
#
|
106
|
+
# @param [ String ] nonce The client nonce.
|
107
|
+
# @param [ String ] rnonce The server nonce.
|
108
|
+
#
|
109
|
+
# @since 1.12.0
|
110
|
+
def initialize(nonce, rnonce)
|
111
|
+
@nonce = nonce
|
112
|
+
@rnonce = rnonce
|
113
|
+
super("Expected server rnonce '#{rnonce}' to start with client nonce '#{nonce}'.")
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
# This exception is raised when the server verifier does not match the
|
118
|
+
# expected signature on the client.
|
119
|
+
#
|
120
|
+
# @since 1.12.0
|
121
|
+
class InvalidSignature < OperationFailure
|
122
|
+
|
123
|
+
# @return [ String ] verifier The server verifier string.
|
124
|
+
attr_reader :verifier
|
125
|
+
|
126
|
+
# @return [ String ] server_signature The expected server signature.
|
127
|
+
attr_reader :server_signature
|
128
|
+
|
129
|
+
# Create the new exception.
|
130
|
+
#
|
131
|
+
# @example Create the new exception.
|
132
|
+
# InvalidSignature.new(verifier, server_signature)
|
133
|
+
#
|
134
|
+
# @param [ String ] verifier The verifier returned from the server.
|
135
|
+
# @param [ String ] server_signature The expected value from the
|
136
|
+
# server.
|
137
|
+
#
|
138
|
+
# @since 1.12.0
|
139
|
+
def initialize(verifier, server_signature)
|
140
|
+
@verifier = verifier
|
141
|
+
@server_signature = server_signature
|
142
|
+
super("Expected server verifier '#{verifier}' to match '#{server_signature}'.")
|
143
|
+
end
|
144
|
+
end
|
88
145
|
end
|
data/lib/mongo/functional.rb
CHANGED
@@ -18,8 +18,11 @@ module Mongo
|
|
18
18
|
module Authentication
|
19
19
|
|
20
20
|
DEFAULT_MECHANISM = 'MONGODB-CR'
|
21
|
-
MECHANISMS = ['GSSAPI', 'MONGODB-CR', 'MONGODB-X509', 'PLAIN']
|
22
|
-
|
21
|
+
MECHANISMS = ['GSSAPI', 'MONGODB-CR', 'MONGODB-X509', 'PLAIN', 'SCRAM-SHA-1']
|
22
|
+
MECHANISM_ERROR = "Must use one of #{MECHANISMS.join(', ')} " +
|
23
|
+
"authentication mechanisms."
|
24
|
+
EXTRA = { 'GSSAPI' => [:service_name, :canonicalize_host_name,
|
25
|
+
:service_realm] }
|
23
26
|
|
24
27
|
# authentication module methods
|
25
28
|
class << self
|
@@ -49,15 +52,13 @@ module Mongo
|
|
49
52
|
# @raise [MongoArgumentError] if the credential set is invalid.
|
50
53
|
# @return [Hash] The validated credential set.
|
51
54
|
def validate_credentials(auth)
|
52
|
-
# set the default auth mechanism if not defined
|
53
|
-
auth[:mechanism] ||= DEFAULT_MECHANISM
|
54
|
-
|
55
55
|
# set the default auth source if not defined
|
56
56
|
auth[:source] = auth[:source] || auth[:db_name] || 'admin'
|
57
57
|
|
58
|
-
if (auth[:mechanism]
|
58
|
+
if password_required?(auth[:mechanism]) && !auth[:password]
|
59
59
|
raise MongoArgumentError,
|
60
|
-
"When using the authentication mechanism
|
60
|
+
"When using the authentication mechanism " +
|
61
|
+
"#{auth[:mechanism].nil? ? 'MONGODB-CR or SCRAM-SHA-1' : auth[:mechanism]} " +
|
61
62
|
"both username and password are required."
|
62
63
|
end
|
63
64
|
# if extra opts exist, validate them
|
@@ -92,6 +93,19 @@ module Mongo
|
|
92
93
|
def hash_password(username, password)
|
93
94
|
Digest::MD5.hexdigest("#{username}:mongo:#{password}")
|
94
95
|
end
|
96
|
+
|
97
|
+
private
|
98
|
+
|
99
|
+
# Does the authentication require a password?
|
100
|
+
#
|
101
|
+
# @param [ String ] mech The authentication mechanism.
|
102
|
+
#
|
103
|
+
# @return [ true, false ] If a password is required.
|
104
|
+
#
|
105
|
+
# @since 1.12.0
|
106
|
+
def password_required?(mech)
|
107
|
+
mech == 'MONGODB-CR' || mech == 'PLAIN' || mech == 'SCRAM-SHA-1' || mech.nil?
|
108
|
+
end
|
95
109
|
end
|
96
110
|
|
97
111
|
# Saves a cache of authentication credentials to the current
|
@@ -104,7 +118,7 @@ module Mongo
|
|
104
118
|
# @param source [String] (nil) The authentication source database
|
105
119
|
# (if different than the current database).
|
106
120
|
# @param mechanism [String] (nil) The authentication mechanism being used
|
107
|
-
# (default: 'MONGODB-CR').
|
121
|
+
# (default: 'MONGODB-CR' or 'SCRAM-SHA-1' if server version >= 2.7.8).
|
108
122
|
# @param extra [Hash] (nil) A optional hash of extra options to be stored with
|
109
123
|
# the credential set.
|
110
124
|
#
|
@@ -131,8 +145,8 @@ module Mongo
|
|
131
145
|
end
|
132
146
|
|
133
147
|
begin
|
134
|
-
socket =
|
135
|
-
|
148
|
+
socket = checkout_reader(:mode => :primary_preferred)
|
149
|
+
issue_authentication(auth, :socket => socket)
|
136
150
|
ensure
|
137
151
|
socket.checkin if socket
|
138
152
|
end
|
@@ -148,7 +162,10 @@ module Mongo
|
|
148
162
|
# @return [Boolean] The result of the operation.
|
149
163
|
def remove_auth(db_name)
|
150
164
|
return false unless @auths
|
151
|
-
@auths.
|
165
|
+
auths = @auths.to_a
|
166
|
+
removed = auths.reject! { |a| a[:source] == db_name }
|
167
|
+
@auths = Set.new(auths)
|
168
|
+
!!removed
|
152
169
|
end
|
153
170
|
|
154
171
|
# Remove all authentication information stored in this connection.
|
@@ -190,6 +207,11 @@ module Mongo
|
|
190
207
|
# @raise [AuthenticationError] Raised if the authentication fails.
|
191
208
|
# @return [Boolean] Result of the authentication operation.
|
192
209
|
def issue_authentication(auth, opts={})
|
210
|
+
# set the default auth mechanism if not defined
|
211
|
+
auth[:mechanism] ||= default_mechanism
|
212
|
+
|
213
|
+
raise MongoArgumentError,
|
214
|
+
MECHANISM_ERROR unless MECHANISMS.include?(auth[:mechanism])
|
193
215
|
result = case auth[:mechanism]
|
194
216
|
when 'MONGODB-CR'
|
195
217
|
issue_cr(auth, opts)
|
@@ -199,6 +221,8 @@ module Mongo
|
|
199
221
|
issue_plain(auth, opts)
|
200
222
|
when 'GSSAPI'
|
201
223
|
issue_gssapi(auth, opts)
|
224
|
+
when 'SCRAM-SHA-1'
|
225
|
+
issue_scram(auth, opts)
|
202
226
|
end
|
203
227
|
|
204
228
|
unless Support.ok?(result)
|
@@ -212,6 +236,86 @@ module Mongo
|
|
212
236
|
|
213
237
|
private
|
214
238
|
|
239
|
+
def default_mechanism
|
240
|
+
max_wire_version >= 3 ? 'SCRAM-SHA-1' : DEFAULT_MECHANISM
|
241
|
+
end
|
242
|
+
|
243
|
+
# Handles copying a database with SCRAM-SHA-1 authentication.
|
244
|
+
#
|
245
|
+
# @api private
|
246
|
+
#
|
247
|
+
# @param [ String ] username The user to authenticate on the
|
248
|
+
# 'from' database.
|
249
|
+
# @param [ String ] password The password for the user authenticated
|
250
|
+
# on the 'from' database.
|
251
|
+
# @param [ String ] from_host The host of the 'from' database.
|
252
|
+
# @param [ String ] from_db Name of the database to copy from.
|
253
|
+
# @param [ String ] to_db Name of the database to copy to.
|
254
|
+
#
|
255
|
+
# @return [ Hash ] The result of the copydb operation.
|
256
|
+
#
|
257
|
+
# @since 1.12.0
|
258
|
+
def copy_db_scram(username, password, from_host, from_db, to_db)
|
259
|
+
auth = { :db_name => from_db,
|
260
|
+
:username => username,
|
261
|
+
:password => password }
|
262
|
+
|
263
|
+
socket = checkout_reader(:mode => :primary_preferred)
|
264
|
+
|
265
|
+
copy_db = { :from_host => from_host, :from_db => from_db, :to_db => to_db }
|
266
|
+
scram = SCRAM.new(auth, Authentication.hash_password(username, password),
|
267
|
+
{ :copy_db => copy_db })
|
268
|
+
result = auth_command(scram.copy_db_start, socket, 'admin').first
|
269
|
+
result = auth_command(scram.copy_db_continue(result), socket, 'admin').first
|
270
|
+
until result['done']
|
271
|
+
result = auth_command(scram.copy_db_continue(result), socket, 'admin').first
|
272
|
+
end
|
273
|
+
socket.checkin
|
274
|
+
result
|
275
|
+
end
|
276
|
+
|
277
|
+
# Handles copying a database with MONGODB-CR authentication.
|
278
|
+
#
|
279
|
+
# @api private
|
280
|
+
#
|
281
|
+
# @param [ String ] username The user to authenticate on the
|
282
|
+
# 'from' database.
|
283
|
+
# @param [ String ] password The password for the user authenticated
|
284
|
+
# on the 'from' database.
|
285
|
+
# @param [ String ] from_host The host of the 'from' database.
|
286
|
+
# @param [ String ] from_db Name of the database to copy from.
|
287
|
+
# @param [ String ] to_db Name of the database to copy to.
|
288
|
+
#
|
289
|
+
# @return [ Hash ] The result of the copydb operation.
|
290
|
+
#
|
291
|
+
# @since 1.12.0
|
292
|
+
def copy_db_mongodb_cr(username, password, from_host, from_db, to_db)
|
293
|
+
oh = BSON::OrderedHash.new
|
294
|
+
oh[:copydb] = 1
|
295
|
+
oh[:fromhost] = from_host
|
296
|
+
oh[:fromdb] = from_db
|
297
|
+
oh[:todb] = to_db
|
298
|
+
|
299
|
+
socket = checkout_reader(:mode => :primary_preferred)
|
300
|
+
|
301
|
+
if username || password
|
302
|
+
unless username && password
|
303
|
+
raise MongoArgumentError,
|
304
|
+
'Both username and password must be supplied for authentication.'
|
305
|
+
end
|
306
|
+
nonce_cmd = BSON::OrderedHash.new
|
307
|
+
nonce_cmd[:copydbgetnonce] = 1
|
308
|
+
nonce_cmd[:fromhost] = from_host
|
309
|
+
result = auth_command(nonce_cmd, socket, 'admin').first
|
310
|
+
oh[:nonce] = result['nonce']
|
311
|
+
oh[:username] = username
|
312
|
+
oh[:key] = Authentication.auth_key(username, password, oh[:nonce])
|
313
|
+
end
|
314
|
+
result = auth_command(oh, socket, 'admin').first
|
315
|
+
socket.checkin
|
316
|
+
result
|
317
|
+
end
|
318
|
+
|
215
319
|
# Handles issuing authentication commands for the MONGODB-CR auth mechanism.
|
216
320
|
#
|
217
321
|
# @param auth [Hash] The authentication credentials to be used.
|
@@ -287,6 +391,29 @@ module Mongo
|
|
287
391
|
raise "In order to use Kerberos, please add the mongo-kerberos gem to your dependencies"
|
288
392
|
end
|
289
393
|
|
394
|
+
# Handles issuing SCRAM-SHA-1 authentication.
|
395
|
+
#
|
396
|
+
# @api private
|
397
|
+
#
|
398
|
+
# @param [ Hash ] auth The authentication credentials.
|
399
|
+
# @param [ Hash ] opts The options.
|
400
|
+
#
|
401
|
+
# @options opts [ Socket ] socket The Socket instance to use.
|
402
|
+
#
|
403
|
+
# @return [ Hash ] The result of the authentication operation.
|
404
|
+
#
|
405
|
+
# @since 1.12.0
|
406
|
+
def issue_scram(auth, opts = {})
|
407
|
+
db_name = auth[:source]
|
408
|
+
scram = SCRAM.new(auth, Authentication.hash_password(auth[:username], auth[:password]))
|
409
|
+
result = auth_command(scram.start, opts[:socket], db_name).first
|
410
|
+
result = auth_command(scram.continue(result), opts[:socket], db_name).first
|
411
|
+
until result['done']
|
412
|
+
result = auth_command(scram.finalize(result), opts[:socket], db_name).first
|
413
|
+
end
|
414
|
+
result
|
415
|
+
end
|
416
|
+
|
290
417
|
# Helper to fetch a nonce value from a given database instance.
|
291
418
|
#
|
292
419
|
# @param database [Mongo::DB] The DB instance to use for issue the nonce command.
|