mongo 2.2.5 → 2.2.6
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/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
|