mongo 2.2.5 → 2.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/lib/mongo/auth/scram/conversation.rb +9 -3
- data/lib/mongo/error.rb +1 -0
- data/lib/mongo/error/unexpected_response.rb +38 -0
- data/lib/mongo/operation/commands/map_reduce/result.rb +1 -1
- data/lib/mongo/operation/commands/user_query.rb +1 -1
- data/lib/mongo/operation/commands/users_info/result.rb +6 -0
- data/lib/mongo/protocol/message.rb +10 -3
- data/lib/mongo/retryable.rb +23 -0
- data/lib/mongo/server/connectable.rb +7 -6
- data/lib/mongo/server/connection.rb +18 -2
- data/lib/mongo/server/connection_pool.rb +4 -6
- data/lib/mongo/server/monitor/connection.rb +6 -3
- data/lib/mongo/uri.rb +7 -8
- data/lib/mongo/version.rb +1 -1
- data/mongo.gemspec +1 -0
- data/spec/mongo/address_spec.rb +2 -2
- data/spec/mongo/auth/cr_spec.rb +1 -1
- data/spec/mongo/auth/ldap_spec.rb +1 -1
- data/spec/mongo/auth/scram_spec.rb +1 -1
- data/spec/mongo/auth/user/view_spec.rb +12 -0
- data/spec/mongo/auth/x509_spec.rb +1 -1
- data/spec/mongo/client_spec.rb +1 -9
- data/spec/mongo/operation/result_spec.rb +3 -3
- data/spec/mongo/operation/write/update_spec.rb +1 -1
- data/spec/mongo/server/connection_spec.rb +168 -4
- data/spec/mongo/server/monitor_spec.rb +34 -4
- data/spec/mongo/server_selector/nearest_spec.rb +4 -4
- data/spec/mongo/server_selector/primary_preferred_spec.rb +4 -4
- data/spec/mongo/server_selector/primary_spec.rb +2 -2
- data/spec/mongo/server_selector/secondary_preferred_spec.rb +4 -4
- data/spec/mongo/server_selector/secondary_spec.rb +3 -3
- data/spec/mongo/server_spec.rb +3 -3
- data/spec/mongo/socket/ssl_spec.rb +1 -1
- data/spec/mongo/uri_spec.rb +124 -23
- data/spec/support/authorization.rb +10 -6
- data/spec/support/shared/server_selector.rb +1 -1
- metadata +18 -3
- 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: df545157946c4036f58eb215212390c7ee6468c2
|
4
|
+
data.tar.gz: feef5fae4e44d03d423ab47d79f6b164f90d0a36
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 765b04848c2b7d821bc1dd1c9e23c56e95b1bdad9bdff7a332bcd2d96a3dff1bbe6c0227b751b07a459688107e0511d5ff0394fd09a266297b3c487f2a4b6bf3
|
7
|
+
data.tar.gz: c45d06e8676ca91af22d72435e1fdea026dab940fb9e9b6f038b7ed5b0e5c6025e8b29a7aa5bb0cf5251ea1e59c90edcf95a8a5c60c69ac4e836736f6b57b402
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data.tar.gz.sig
CHANGED
Binary file
|
@@ -290,7 +290,7 @@ module Mongo
|
|
290
290
|
#
|
291
291
|
# @since 2.0.0
|
292
292
|
def h(string)
|
293
|
-
|
293
|
+
digest.digest(string)
|
294
294
|
end
|
295
295
|
|
296
296
|
# HI algorithm implementation.
|
@@ -305,7 +305,7 @@ module Mongo
|
|
305
305
|
data,
|
306
306
|
Base64.strict_decode64(salt),
|
307
307
|
iterations,
|
308
|
-
|
308
|
+
digest.size
|
309
309
|
)
|
310
310
|
end
|
311
311
|
|
@@ -317,7 +317,7 @@ module Mongo
|
|
317
317
|
#
|
318
318
|
# @since 2.0.0
|
319
319
|
def hmac(data, key)
|
320
|
-
OpenSSL::HMAC.digest(
|
320
|
+
OpenSSL::HMAC.digest(digest, data, key)
|
321
321
|
end
|
322
322
|
|
323
323
|
# Get the iterations from the server response.
|
@@ -451,6 +451,12 @@ module Mongo
|
|
451
451
|
raise Unauthorized.new(user) unless reply.documents[0][Operation::Result::OK] == 1
|
452
452
|
@reply = reply
|
453
453
|
end
|
454
|
+
|
455
|
+
private
|
456
|
+
|
457
|
+
def digest
|
458
|
+
@digest ||= OpenSSL::Digest::SHA1.new.freeze
|
459
|
+
end
|
454
460
|
end
|
455
461
|
end
|
456
462
|
end
|
data/lib/mongo/error.rb
CHANGED
@@ -99,5 +99,6 @@ require 'mongo/error/socket_error'
|
|
99
99
|
require 'mongo/error/socket_timeout_error'
|
100
100
|
require 'mongo/error/unchangeable_collection_option'
|
101
101
|
require 'mongo/error/unexpected_chunk_length'
|
102
|
+
require 'mongo/error/unexpected_response'
|
102
103
|
require 'mongo/error/missing_file_chunk'
|
103
104
|
require 'mongo/error/unsupported_features'
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# Copyright (C) 2014-2015 MongoDB, Inc.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
module Mongo
|
16
|
+
class Error
|
17
|
+
|
18
|
+
# Raised if the response read from the socket does not match the latest query.
|
19
|
+
#
|
20
|
+
# @since 2.2.6
|
21
|
+
class UnexpectedResponse < Error
|
22
|
+
|
23
|
+
# Create the new exception.
|
24
|
+
#
|
25
|
+
# @example Create the new exception.
|
26
|
+
# Mongo::Error::UnexpectedResponse.new(expected_response_to, response_to)
|
27
|
+
#
|
28
|
+
# @param [ Integer ] expected_response_to The last request id sent.
|
29
|
+
# @param [ Integer ] response_to The actual response_to of the reply.
|
30
|
+
#
|
31
|
+
# @since 2.2.6
|
32
|
+
def initialize(expected_response_to, response_to)
|
33
|
+
super("Unexpected response. Got response for request ID #{response_to} " +
|
34
|
+
"but expected response for request ID #{expected_response_to}")
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -44,7 +44,7 @@ module Mongo
|
|
44
44
|
# @since 2.1.0
|
45
45
|
def execute(context)
|
46
46
|
if context.features.users_info_enabled?
|
47
|
-
UsersInfo.new(spec).execute(context)
|
47
|
+
UsersInfo.new(spec).execute(context).validate!
|
48
48
|
else
|
49
49
|
context.with_connection do |connection|
|
50
50
|
Result.new(connection.dispatch([ message(context) ])).validate!
|
@@ -109,8 +109,8 @@ module Mongo
|
|
109
109
|
# @param [ IO ] io Stream containing a message
|
110
110
|
#
|
111
111
|
# @return [ Message ] Instance of a Message class
|
112
|
-
def self.deserialize(io, max_message_size = MAX_MESSAGE_SIZE)
|
113
|
-
length = deserialize_header(BSON::ByteBuffer.new(io.read(16)))
|
112
|
+
def self.deserialize(io, max_message_size = MAX_MESSAGE_SIZE, expected_response_to = nil)
|
113
|
+
length, request_id, response_to, op_code = deserialize_header(BSON::ByteBuffer.new(io.read(16)))
|
114
114
|
|
115
115
|
# Protection from potential DOS man-in-the-middle attacks. See
|
116
116
|
# DRIVERS-276.
|
@@ -118,8 +118,15 @@ module Mongo
|
|
118
118
|
raise Error::MaxMessageSize.new(max_message_size)
|
119
119
|
end
|
120
120
|
|
121
|
+
# Protection against returning the response to a previous request. See
|
122
|
+
# RUBY-1117
|
123
|
+
if expected_response_to && response_to != expected_response_to
|
124
|
+
raise Error::UnexpectedResponse.new(expected_response_to, response_to)
|
125
|
+
end
|
126
|
+
|
121
127
|
buffer = BSON::ByteBuffer.new(io.read(length - 16))
|
122
128
|
message = allocate
|
129
|
+
|
123
130
|
fields.each do |field|
|
124
131
|
if field[:multi]
|
125
132
|
deserialize_array(message, buffer, field)
|
@@ -228,7 +235,7 @@ module Mongo
|
|
228
235
|
# @param io [IO] Stream containing the header.
|
229
236
|
# @return [Array<Fixnum>] Deserialized header.
|
230
237
|
def self.deserialize_header(io)
|
231
|
-
|
238
|
+
Header.deserialize(io)
|
232
239
|
end
|
233
240
|
|
234
241
|
# A method for declaring a message field
|
data/lib/mongo/retryable.rb
CHANGED
@@ -67,6 +67,29 @@ module Mongo
|
|
67
67
|
end
|
68
68
|
end
|
69
69
|
|
70
|
+
# Execute a read operation with a single retry.
|
71
|
+
#
|
72
|
+
# @api private
|
73
|
+
#
|
74
|
+
# @example Execute the read.
|
75
|
+
# read_with_one_retry do
|
76
|
+
# ...
|
77
|
+
# end
|
78
|
+
#
|
79
|
+
# @note This only retries read operations on socket errors.
|
80
|
+
#
|
81
|
+
# @param [ Proc ] block The block to execute.
|
82
|
+
#
|
83
|
+
# @return [ Result ] The result of the operation.
|
84
|
+
#
|
85
|
+
# @since 2.2.6
|
86
|
+
def read_with_one_retry(&block)
|
87
|
+
block.call
|
88
|
+
rescue Error::SocketError,
|
89
|
+
Error::SocketTimeoutError
|
90
|
+
block.call
|
91
|
+
end
|
92
|
+
|
70
93
|
# Execute a write operation with a retry.
|
71
94
|
#
|
72
95
|
# @api private
|
@@ -88,10 +88,11 @@ module Mongo
|
|
88
88
|
ensure_same_process!
|
89
89
|
connect!
|
90
90
|
begin
|
91
|
-
yield socket
|
92
|
-
|
93
|
-
|
94
|
-
|
91
|
+
result = yield socket
|
92
|
+
success = true
|
93
|
+
result
|
94
|
+
ensure
|
95
|
+
success or disconnect!
|
95
96
|
end
|
96
97
|
end
|
97
98
|
|
@@ -102,9 +103,9 @@ module Mongo
|
|
102
103
|
end
|
103
104
|
end
|
104
105
|
|
105
|
-
def read
|
106
|
+
def read(request_id = nil)
|
106
107
|
ensure_connected do |socket|
|
107
|
-
Protocol::Reply.deserialize(socket, max_message_size)
|
108
|
+
Protocol::Reply.deserialize(socket, max_message_size, request_id)
|
108
109
|
end
|
109
110
|
end
|
110
111
|
end
|
@@ -21,6 +21,7 @@ module Mongo
|
|
21
21
|
class Connection
|
22
22
|
include Connectable
|
23
23
|
include Monitoring::Publishable
|
24
|
+
include Retryable
|
24
25
|
extend Forwardable
|
25
26
|
|
26
27
|
# The ping command.
|
@@ -62,6 +63,9 @@ module Mongo
|
|
62
63
|
authenticate!
|
63
64
|
end
|
64
65
|
true
|
66
|
+
rescue Mongo::Auth::Unauthorized => e
|
67
|
+
disconnect!
|
68
|
+
raise e
|
65
69
|
end
|
66
70
|
|
67
71
|
# Disconnect the connection.
|
@@ -155,17 +159,29 @@ module Mongo
|
|
155
159
|
|
156
160
|
def deliver(messages)
|
157
161
|
write(messages)
|
158
|
-
messages.last.replyable? ? read : nil
|
162
|
+
messages.last.replyable? ? read(messages.last.request_id) : nil
|
159
163
|
end
|
160
164
|
|
161
165
|
def authenticate!
|
162
166
|
if options[:user]
|
163
|
-
default_mechanism = @server.features.scram_sha_1_enabled? ? :scram : :mongodb_cr
|
164
167
|
user = Auth::User.new(Options::Redacted.new(:auth_mech => default_mechanism).merge(options))
|
165
168
|
Auth.get(user).login(self)
|
166
169
|
end
|
167
170
|
end
|
168
171
|
|
172
|
+
def default_mechanism
|
173
|
+
if socket && socket.connectable?
|
174
|
+
socket.write(Monitor::Connection::ISMASTER_BYTES)
|
175
|
+
ismaster = Protocol::Reply.deserialize(socket, max_message_size).documents[0]
|
176
|
+
min_wire_version = ismaster[Description::MIN_WIRE_VERSION] || Description::LEGACY_WIRE_VERSION
|
177
|
+
max_wire_version = ismaster[Description::MAX_WIRE_VERSION] || Description::LEGACY_WIRE_VERSION
|
178
|
+
features = Description::Features.new(min_wire_version..max_wire_version)
|
179
|
+
(features.scram_sha_1_enabled? || @server.features.scram_sha_1_enabled?) ? :scram : :mongodb_cr
|
180
|
+
else
|
181
|
+
@server.features.scram_sha_1_enabled? ? :scram : :mongodb_cr
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
169
185
|
def write(messages, buffer = BSON::ByteBuffer.new)
|
170
186
|
start_size = 0
|
171
187
|
messages.each do |message|
|
@@ -103,12 +103,10 @@ module Mongo
|
|
103
103
|
#
|
104
104
|
# @since 2.0.0
|
105
105
|
def with_connection
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
checkin(connection) if connection
|
111
|
-
end
|
106
|
+
connection = checkout
|
107
|
+
yield(connection)
|
108
|
+
ensure
|
109
|
+
checkin(connection) if connection
|
112
110
|
end
|
113
111
|
|
114
112
|
private
|
@@ -20,6 +20,7 @@ module Mongo
|
|
20
20
|
#
|
21
21
|
# @since 2.0.0
|
22
22
|
class Connection
|
23
|
+
include Retryable
|
23
24
|
include Connectable
|
24
25
|
|
25
26
|
# The command used for determining server status.
|
@@ -52,8 +53,10 @@ module Mongo
|
|
52
53
|
# @since 2.2.0
|
53
54
|
def ismaster
|
54
55
|
ensure_connected do |socket|
|
55
|
-
|
56
|
-
|
56
|
+
read_with_one_retry do
|
57
|
+
socket.write(ISMASTER_BYTES)
|
58
|
+
Protocol::Reply.deserialize(socket).documents[0]
|
59
|
+
end
|
57
60
|
end
|
58
61
|
end
|
59
62
|
|
@@ -69,7 +72,7 @@ module Mongo
|
|
69
72
|
#
|
70
73
|
# @since 2.0.0
|
71
74
|
def connect!
|
72
|
-
unless socket
|
75
|
+
unless socket && socket.connectable?
|
73
76
|
@socket = address.socket(timeout, ssl_options)
|
74
77
|
socket.connect!
|
75
78
|
end
|
data/lib/mongo/uri.rb
CHANGED
@@ -158,9 +158,9 @@ module Mongo
|
|
158
158
|
# @since 2.0.0
|
159
159
|
READ_MODE_MAP = {
|
160
160
|
'primary' => :primary,
|
161
|
-
'
|
161
|
+
'primarypreferred' => :primary_preferred,
|
162
162
|
'secondary' => :secondary,
|
163
|
-
'
|
163
|
+
'secondarypreferred' => :secondary_preferred,
|
164
164
|
'nearest' => :nearest
|
165
165
|
}.freeze
|
166
166
|
|
@@ -387,13 +387,12 @@ module Mongo
|
|
387
387
|
uri_option 'connect', :connect
|
388
388
|
|
389
389
|
# Auth Options
|
390
|
-
uri_option 'authsource', :
|
390
|
+
uri_option 'authsource', :auth_source, :type => :auth_source
|
391
391
|
uri_option 'authmechanism', :auth_mech, :type => :auth_mech
|
392
|
-
uri_option 'authmechanismproperties', :auth_mech_properties, :
|
393
|
-
:type => :auth_mech_props
|
392
|
+
uri_option 'authmechanismproperties', :auth_mech_properties, :type => :auth_mech_props
|
394
393
|
|
395
394
|
# Casts option values that do not have a specifically provided
|
396
|
-
#
|
395
|
+
# transformation to the appropriate type.
|
397
396
|
#
|
398
397
|
# @param value [String] The value to be cast.
|
399
398
|
#
|
@@ -500,7 +499,7 @@ module Mongo
|
|
500
499
|
#
|
501
500
|
# @return [Symbol] The transformed authentication mechanism.
|
502
501
|
def auth_mech(value)
|
503
|
-
AUTH_MECH_MAP[value]
|
502
|
+
AUTH_MECH_MAP[value.upcase]
|
504
503
|
end
|
505
504
|
|
506
505
|
# Read preference mode transformation.
|
@@ -509,7 +508,7 @@ module Mongo
|
|
509
508
|
#
|
510
509
|
# @return [Symbol] The read mode symbol.
|
511
510
|
def read_mode(value)
|
512
|
-
READ_MODE_MAP[value]
|
511
|
+
READ_MODE_MAP[value.downcase]
|
513
512
|
end
|
514
513
|
|
515
514
|
# Read preference tags transformation.
|
data/lib/mongo/version.rb
CHANGED
data/mongo.gemspec
CHANGED
data/spec/mongo/address_spec.rb
CHANGED
@@ -209,11 +209,11 @@ describe Mongo::Address do
|
|
209
209
|
context 'when providing a DNS entry that resolves to both IPv6 and IPv4' do
|
210
210
|
|
211
211
|
let(:address) do
|
212
|
-
|
212
|
+
default_address
|
213
213
|
end
|
214
214
|
|
215
215
|
let(:host) do
|
216
|
-
|
216
|
+
address.host
|
217
217
|
end
|
218
218
|
|
219
219
|
before do
|
data/spec/mongo/auth/cr_spec.rb
CHANGED
@@ -139,5 +139,17 @@ describe Mongo::Auth::User::View do
|
|
139
139
|
end
|
140
140
|
end
|
141
141
|
|
142
|
+
context 'when a user is not authorized' do
|
143
|
+
|
144
|
+
let(:view) do
|
145
|
+
described_class.new(unauthorized_client.database)
|
146
|
+
end
|
147
|
+
|
148
|
+
it 'raises an OperationFailure' do
|
149
|
+
expect{
|
150
|
+
view.info('emily')
|
151
|
+
}.to raise_exception(Mongo::Error::OperationFailure)
|
152
|
+
end
|
153
|
+
end
|
142
154
|
end
|
143
155
|
end
|