mongo 2.11.0 → 2.11.5
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/Rakefile +24 -0
- data/lib/mongo/address.rb +53 -37
- data/lib/mongo/auth.rb +30 -10
- data/lib/mongo/auth/cr.rb +1 -0
- data/lib/mongo/auth/cr/conversation.rb +13 -13
- data/lib/mongo/auth/ldap.rb +2 -1
- data/lib/mongo/auth/ldap/conversation.rb +9 -12
- data/lib/mongo/auth/scram.rb +1 -0
- data/lib/mongo/auth/scram/conversation.rb +36 -27
- data/lib/mongo/auth/user.rb +7 -1
- data/lib/mongo/auth/x509.rb +2 -1
- data/lib/mongo/auth/x509/conversation.rb +9 -9
- data/lib/mongo/bulk_write/transformable.rb +3 -3
- data/lib/mongo/client.rb +17 -6
- data/lib/mongo/cluster.rb +67 -49
- data/lib/mongo/cluster/sdam_flow.rb +87 -3
- data/lib/mongo/collection/view/readable.rb +3 -1
- data/lib/mongo/collection/view/writable.rb +3 -3
- data/lib/mongo/cursor/builder/kill_cursors_command.rb +8 -1
- data/lib/mongo/cursor/builder/op_kill_cursors.rb +8 -1
- data/lib/mongo/database.rb +1 -1
- data/lib/mongo/grid/file.rb +5 -0
- data/lib/mongo/grid/file/chunk.rb +2 -0
- data/lib/mongo/grid/fs_bucket.rb +15 -13
- data/lib/mongo/grid/stream/write.rb +9 -3
- data/lib/mongo/protocol/serializers.rb +12 -2
- data/lib/mongo/retryable.rb +33 -8
- data/lib/mongo/server.rb +13 -6
- data/lib/mongo/server/connection.rb +15 -8
- data/lib/mongo/server/connection_base.rb +7 -4
- data/lib/mongo/server/description.rb +34 -21
- data/lib/mongo/server/monitor.rb +1 -1
- data/lib/mongo/server/monitor/connection.rb +2 -3
- data/lib/mongo/session.rb +10 -10
- data/lib/mongo/socket.rb +10 -1
- data/lib/mongo/uri.rb +1 -1
- data/lib/mongo/version.rb +1 -1
- data/mongo.gemspec +1 -1
- data/spec/README.md +13 -0
- data/spec/integration/auth_spec.rb +27 -8
- data/spec/integration/bson_symbol_spec.rb +34 -0
- data/spec/integration/client_construction_spec.rb +14 -0
- data/spec/integration/client_options_spec.rb +5 -5
- data/spec/integration/connection_spec.rb +57 -9
- data/spec/integration/crud_spec.rb +45 -0
- data/spec/integration/cursor_reaping_spec.rb +2 -1
- data/spec/integration/grid_fs_bucket_spec.rb +48 -0
- data/spec/integration/retryable_errors_spec.rb +204 -39
- data/spec/integration/retryable_writes_spec.rb +36 -36
- data/spec/integration/size_limit_spec.rb~12e1e9c4f... RUBY-2242 Fix zlib compression (#2021) +98 -0
- data/spec/lite_spec_helper.rb +1 -0
- data/spec/mongo/address_spec.rb +19 -13
- data/spec/mongo/auth/ldap/conversation_spec.rb +1 -1
- data/spec/mongo/auth/scram/conversation_spec.rb +25 -14
- data/spec/mongo/auth/user/view_spec.rb +36 -1
- data/spec/mongo/auth/user_spec.rb +12 -0
- data/spec/mongo/auth/x509/conversation_spec.rb +1 -1
- data/spec/mongo/bulk_write_spec.rb +2 -2
- data/spec/mongo/client_construction_spec.rb +1 -21
- data/spec/mongo/cluster_spec.rb +57 -0
- data/spec/mongo/collection/view/map_reduce_spec.rb +1 -1
- data/spec/mongo/collection_spec.rb +26 -2
- data/spec/mongo/cursor/builder/op_kill_cursors_spec.rb +56 -0
- data/spec/mongo/server/connection_spec.rb +76 -8
- data/spec/mongo/server/monitor/connection_spec.rb +14 -7
- data/spec/mongo/socket/ssl_spec.rb +132 -98
- data/spec/mongo/socket/tcp_spec.rb +1 -9
- data/spec/mongo/uri_spec.rb +1 -1
- data/spec/runners/sdam/verifier.rb +91 -0
- data/spec/spec_tests/data/sdam/rs/primary_address_change.yml +29 -0
- data/spec/spec_tests/data/sdam/rs/primary_mismatched_me.yml +27 -23
- data/spec/spec_tests/data/sdam/rs/primary_to_no_primary_mismatched_me.yml +56 -79
- data/spec/spec_tests/data/sdam/sharded/primary_address_change.yml +21 -0
- data/spec/spec_tests/data/sdam/sharded/primary_mismatched_me.yml +22 -0
- data/spec/spec_tests/data/sdam/single/primary_address_change.yml +24 -0
- data/spec/spec_tests/data/sdam/single/primary_mismatched_me.yml +25 -0
- data/spec/spec_tests/data/sdam_monitoring/replica_set_with_me_mismatch.yml +159 -0
- data/spec/spec_tests/data/sdam_monitoring/{replica_set_other_seed.yml → replica_set_with_primary_change.yml} +97 -101
- data/spec/spec_tests/data/sdam_monitoring/replica_set_with_primary_removal.yml +22 -18
- data/spec/spec_tests/data/sdam_monitoring/standalone_to_rs_with_me_mismatch.yml +90 -0
- data/spec/spec_tests/sdam_monitoring_spec.rb +9 -4
- data/spec/support/cluster_config.rb +36 -0
- data/spec/support/cluster_tools.rb +5 -3
- data/spec/support/command_monitoring.rb +1 -1
- data/spec/support/constraints.rb +18 -18
- data/spec/support/lite_constraints.rb +8 -0
- data/spec/support/sdam_monitoring.rb +0 -115
- data/spec/support/server_discovery_and_monitoring.rb +2 -0
- data/spec/support/spec_config.rb +1 -1
- data/spec/support/utils.rb +11 -1
- metadata +687 -659
- metadata.gz.sig +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8c345d3cf6aa92723002548f8e1e14be65bdfb0969eb05756d510f51a7a6b4ec
|
4
|
+
data.tar.gz: 306c19eafbaee190b5f865beedc5a149b46c5d45aeae509f85390c6e554c25e2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 80389668e920fe61e0aedad8ae4bf6973cc3f3f150a7e6a49514aee5aec7e062e00851abcabd273efacffc2c080373d0036cc74e49f3fab8607ab133f901e1b8
|
7
|
+
data.tar.gz: 41c28e98cef6df75eb38e4a043c3c4bfce8623a3f68a10522a02d22984a31d0283af5113d8dd8c4ba37aa7df373ff400a9a1359acb9731c1a433c370976b2aa7
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data.tar.gz.sig
CHANGED
Binary file
|
data/Rakefile
CHANGED
@@ -34,6 +34,30 @@ namespace :spec do
|
|
34
34
|
SpecSetup.new.run
|
35
35
|
end
|
36
36
|
|
37
|
+
desc 'Waits for sessions to be available in the deployment'
|
38
|
+
task :wait_for_sessions do
|
39
|
+
$: << File.join(File.dirname(__FILE__), 'spec')
|
40
|
+
|
41
|
+
require 'support/utils'
|
42
|
+
require 'support/spec_config'
|
43
|
+
require 'support/client_registry'
|
44
|
+
|
45
|
+
client = ClientRegistry.instance.global_client('authorized')
|
46
|
+
client.database.command(ping: 1)
|
47
|
+
deadline = Time.now + 300
|
48
|
+
while Time.now < deadline
|
49
|
+
if client.cluster.send(:sessions_supported?)
|
50
|
+
break
|
51
|
+
end
|
52
|
+
sleep 1
|
53
|
+
client.close
|
54
|
+
client.reconnect
|
55
|
+
end
|
56
|
+
unless client.cluster.send(:sessions_supported?)
|
57
|
+
raise "Sessions did not become supported in the allowed time"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
37
61
|
desc 'Prints configuration used by the test suite'
|
38
62
|
task :config do
|
39
63
|
$: << File.join(File.dirname(__FILE__), 'spec')
|
data/lib/mongo/address.rb
CHANGED
@@ -66,6 +66,8 @@ module Mongo
|
|
66
66
|
# @param [ String ] seed The provided address.
|
67
67
|
# @param [ Hash ] options The address options.
|
68
68
|
#
|
69
|
+
# @option options [ Float ] :connect_timeout Connect timeout.
|
70
|
+
#
|
69
71
|
# @since 2.0.0
|
70
72
|
def initialize(seed, options = {})
|
71
73
|
if seed.nil?
|
@@ -85,6 +87,9 @@ module Mongo
|
|
85
87
|
# @return [ Integer ] port The port.
|
86
88
|
attr_reader :port
|
87
89
|
|
90
|
+
# @api private
|
91
|
+
attr_reader :options
|
92
|
+
|
88
93
|
# Check equality of the address to another.
|
89
94
|
#
|
90
95
|
# @example Check address equality.
|
@@ -138,13 +143,30 @@ module Mongo
|
|
138
143
|
"#<Mongo::Address:0x#{object_id} address=#{to_s}>"
|
139
144
|
end
|
140
145
|
|
141
|
-
# Get a socket for the
|
146
|
+
# Get a socket for the address stored in this object, given the options.
|
147
|
+
#
|
148
|
+
# If the address stored in this object looks like a Unix path, this method
|
149
|
+
# returns a Unix domain socket for this path.
|
142
150
|
#
|
143
|
-
#
|
144
|
-
#
|
145
|
-
#
|
146
|
-
#
|
147
|
-
#
|
151
|
+
# Otherwise, this method attempts to resolve the address stored in
|
152
|
+
# this object to IPv4 and IPv6 addresses using +Socket#getaddrinfo+, then
|
153
|
+
# connects to the resulting addresses and returns the socket of the first
|
154
|
+
# successful connection. The order in which address families (IPv4/IPV6)
|
155
|
+
# are tried is the same order in which the addresses are returned by
|
156
|
+
# +getaddrinfo+, and is determined by the host system.
|
157
|
+
#
|
158
|
+
# Name resolution is performed on each +socket+ call. This is done so that
|
159
|
+
# any changes to which addresses the host names used as seeds or in
|
160
|
+
# server configuration resolve to are immediately noticed by the driver,
|
161
|
+
# even if a socket has been connected to the affected host name/address
|
162
|
+
# before. However, note that DNS TTL values may still affect when a change
|
163
|
+
# to a host address is noticed by the driver.
|
164
|
+
#
|
165
|
+
# This method propagates any exceptions raised during DNS resolution and
|
166
|
+
# subsequent connection attempts. In case of a host name resolving to
|
167
|
+
# multiple IP addresses, the error raised by the last attempt is propagated
|
168
|
+
# to the caller. This method does not map exceptions to Mongo::Error
|
169
|
+
# subclasses, and may raise any subclass of Exception.
|
148
170
|
#
|
149
171
|
# @example Get a socket.
|
150
172
|
# address.socket(5, :ssl => true)
|
@@ -155,11 +177,34 @@ module Mongo
|
|
155
177
|
#
|
156
178
|
# @option options [ Float ] :connect_timeout Connect timeout.
|
157
179
|
#
|
158
|
-
# @return [ Mongo::Socket::SSL
|
180
|
+
# @return [ Mongo::Socket::SSL | Mongo::Socket::TCP | Mongo::Socket::Unix ]
|
181
|
+
# The socket.
|
182
|
+
#
|
183
|
+
# @raise [ Exception ] If network connection failed.
|
159
184
|
#
|
160
185
|
# @since 2.0.0
|
161
186
|
def socket(socket_timeout, ssl_options = {}, options = {})
|
162
|
-
|
187
|
+
if seed.downcase =~ Unix::MATCH
|
188
|
+
specific_address = Unix.new(seed.downcase)
|
189
|
+
return specific_address.socket(socket_timeout, ssl_options, options)
|
190
|
+
end
|
191
|
+
|
192
|
+
options = {
|
193
|
+
connect_timeout: Server::CONNECT_TIMEOUT,
|
194
|
+
}.update(options)
|
195
|
+
|
196
|
+
family = (host == LOCALHOST) ? ::Socket::AF_INET : ::Socket::AF_UNSPEC
|
197
|
+
error = nil
|
198
|
+
::Socket.getaddrinfo(host, nil, family, ::Socket::SOCK_STREAM).each do |info|
|
199
|
+
begin
|
200
|
+
specific_address = FAMILY_MAP[info[4]].new(info[3], port, host)
|
201
|
+
socket = specific_address.socket(socket_timeout, ssl_options, options)
|
202
|
+
return socket
|
203
|
+
rescue IOError, SystemCallError, Error::SocketTimeoutError, Error::SocketError => e
|
204
|
+
error = e
|
205
|
+
end
|
206
|
+
end
|
207
|
+
raise error
|
163
208
|
end
|
164
209
|
|
165
210
|
# Get the address as a string.
|
@@ -182,37 +227,8 @@ module Mongo
|
|
182
227
|
end
|
183
228
|
end
|
184
229
|
|
185
|
-
# @api private
|
186
|
-
def connect_timeout
|
187
|
-
@connect_timeout ||= @options[:connect_timeout] || Server::CONNECT_TIMEOUT
|
188
|
-
end
|
189
|
-
|
190
230
|
private
|
191
231
|
|
192
|
-
# To determine which address the socket will connect to, the driver will
|
193
|
-
# attempt to connect to each IP address returned by Socket::getaddrinfo in
|
194
|
-
# sequence. Once a successful connection is made, a resolver with that
|
195
|
-
# IP address specified is returned. If no successful connection is
|
196
|
-
# made, the error made by the last connection attempt is raised.
|
197
|
-
def create_resolver(ssl_options)
|
198
|
-
return Unix.new(seed.downcase) if seed.downcase =~ Unix::MATCH
|
199
|
-
|
200
|
-
family = (host == LOCALHOST) ? ::Socket::AF_INET : ::Socket::AF_UNSPEC
|
201
|
-
error = nil
|
202
|
-
::Socket.getaddrinfo(host, nil, family, ::Socket::SOCK_STREAM).each do |info|
|
203
|
-
begin
|
204
|
-
specific_address = FAMILY_MAP[info[4]].new(info[3], port, host)
|
205
|
-
socket = specific_address.socket(
|
206
|
-
connect_timeout, ssl_options, connect_timeout: connect_timeout)
|
207
|
-
socket.close
|
208
|
-
return specific_address
|
209
|
-
rescue IOError, SystemCallError, Error::SocketTimeoutError, Error::SocketError => e
|
210
|
-
error = e
|
211
|
-
end
|
212
|
-
end
|
213
|
-
raise error
|
214
|
-
end
|
215
|
-
|
216
232
|
def parse_host_port
|
217
233
|
address = seed.downcase
|
218
234
|
case address
|
data/lib/mongo/auth.rb
CHANGED
@@ -110,25 +110,45 @@ module Mongo
|
|
110
110
|
# @param [ String ] used_mechanism Auth mechanism actually used for
|
111
111
|
# authentication. This is a full string like SCRAM-SHA-256.
|
112
112
|
# @param [ String ] message The error message returned by the server.
|
113
|
+
# @param [ Server ] server The server instance that authentication
|
114
|
+
# was attempted against.
|
113
115
|
#
|
114
116
|
# @since 2.0.0
|
115
|
-
def initialize(user, used_mechanism: nil, message: nil
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
117
|
+
def initialize(user, used_mechanism: nil, message: nil,
|
118
|
+
server: nil
|
119
|
+
)
|
120
|
+
configured_bits = []
|
121
|
+
used_bits = [
|
122
|
+
"auth source: #{user.auth_source}",
|
123
|
+
]
|
124
|
+
|
125
|
+
if user.mechanism
|
126
|
+
configured_bits << "mechanism: #{user.mechanism}"
|
120
127
|
end
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
128
|
+
|
129
|
+
if used_mechanism
|
130
|
+
used_bits << "used mechanism: #{used_mechanism}"
|
131
|
+
end
|
132
|
+
|
133
|
+
if server
|
134
|
+
used_bits << "used server: #{server.address} (#{server.status})"
|
125
135
|
end
|
136
|
+
|
126
137
|
used_user = if user.mechanism == :mongodb_x509
|
127
138
|
'Client certificate'
|
128
139
|
else
|
129
140
|
"User #{user.name}"
|
130
141
|
end
|
131
|
-
|
142
|
+
|
143
|
+
if configured_bits.empty?
|
144
|
+
configured_bits = ''
|
145
|
+
else
|
146
|
+
configured_bits = " (#{configured_bits.join(', ')})"
|
147
|
+
end
|
148
|
+
|
149
|
+
used_bits = " (#{used_bits.join(', ')})"
|
150
|
+
|
151
|
+
msg = "#{used_user}#{configured_bits} is not authorized to access #{user.database}#{used_bits}"
|
132
152
|
if message
|
133
153
|
msg += ': ' + message
|
134
154
|
end
|
data/lib/mongo/auth/cr.rb
CHANGED
@@ -23,6 +23,7 @@ module Mongo
|
|
23
23
|
# @deprecated MONGODB-CR authentication mechanism is deprecated
|
24
24
|
# as of MongoDB 3.6. Support for it in the Ruby driver will be
|
25
25
|
# removed in driver version 3.0. Please use SCRAM instead.
|
26
|
+
# @api private
|
26
27
|
class CR
|
27
28
|
|
28
29
|
# The authentication mechinism string.
|
@@ -52,13 +52,14 @@ module Mongo
|
|
52
52
|
#
|
53
53
|
# @param [ Protocol::Message ] reply The reply of the previous
|
54
54
|
# message.
|
55
|
-
# @param [ Mongo::Server::Connection ] connection The connection being
|
55
|
+
# @param [ Mongo::Server::Connection ] connection The connection being
|
56
|
+
# authenticated.
|
56
57
|
#
|
57
58
|
# @return [ Protocol::Query ] The next message to send.
|
58
59
|
#
|
59
60
|
# @since 2.0.0
|
60
|
-
def continue(reply, connection
|
61
|
-
validate!(reply)
|
61
|
+
def continue(reply, connection)
|
62
|
+
validate!(reply, connection.server)
|
62
63
|
if connection && connection.features.op_msg_enabled?
|
63
64
|
selector = LOGIN.merge(user: user.name, nonce: nonce, key: user.auth_key(nonce))
|
64
65
|
selector[Protocol::Msg::DATABASE_IDENTIFIER] = user.auth_source
|
@@ -78,29 +79,28 @@ module Mongo
|
|
78
79
|
# Finalize the CR conversation. This is meant to be iterated until
|
79
80
|
# the provided reply indicates the conversation is finished.
|
80
81
|
#
|
81
|
-
# @example Finalize the conversation.
|
82
|
-
# conversation.finalize(reply)
|
83
|
-
#
|
84
82
|
# @param [ Protocol::Message ] reply The reply of the previous
|
85
83
|
# message.
|
84
|
+
# @param [ Server::Connection ] connection The connection being
|
85
|
+
# authenticated.
|
86
86
|
#
|
87
87
|
# @return [ Protocol::Query ] The next message to send.
|
88
88
|
#
|
89
89
|
# @since 2.0.0
|
90
|
-
def finalize(reply, connection
|
91
|
-
validate!(reply)
|
90
|
+
def finalize(reply, connection)
|
91
|
+
validate!(reply, connection.server)
|
92
92
|
end
|
93
93
|
|
94
94
|
# Start the CR conversation. This returns the first message that
|
95
95
|
# needs to be sent to the server.
|
96
96
|
#
|
97
|
-
# @
|
98
|
-
#
|
97
|
+
# @param [ Server::Connection ] connection The connection being
|
98
|
+
# authenticated.
|
99
99
|
#
|
100
100
|
# @return [ Protocol::Query ] The first CR conversation message.
|
101
101
|
#
|
102
102
|
# @since 2.0.0
|
103
|
-
def start(connection
|
103
|
+
def start(connection)
|
104
104
|
if connection && connection.features.op_msg_enabled?
|
105
105
|
selector = Auth::GET_NONCE.merge(Protocol::Msg::DATABASE_IDENTIFIER => user.auth_source)
|
106
106
|
cluster_time = connection.mongos? && connection.cluster_time
|
@@ -129,9 +129,9 @@ module Mongo
|
|
129
129
|
|
130
130
|
private
|
131
131
|
|
132
|
-
def validate!(reply)
|
132
|
+
def validate!(reply, server)
|
133
133
|
if reply.documents[0][Operation::Result::OK] != 1
|
134
|
-
raise Unauthorized.new(user, used_mechanism: MECHANISM)
|
134
|
+
raise Unauthorized.new(user, used_mechanism: MECHANISM, server: server)
|
135
135
|
end
|
136
136
|
@nonce = reply.documents[0][Auth::NONCE]
|
137
137
|
@reply = reply
|
data/lib/mongo/auth/ldap.rb
CHANGED
@@ -20,6 +20,7 @@ module Mongo
|
|
20
20
|
# Defines behavior for LDAP Proxy authentication.
|
21
21
|
#
|
22
22
|
# @since 2.0.0
|
23
|
+
# @api private
|
23
24
|
class LDAP
|
24
25
|
|
25
26
|
# The authentication mechinism string.
|
@@ -56,7 +57,7 @@ module Mongo
|
|
56
57
|
conversation = Conversation.new(user)
|
57
58
|
reply = connection.dispatch([ conversation.start(connection) ])
|
58
59
|
connection.update_cluster_time(Operation::Result.new(reply))
|
59
|
-
conversation.finalize(reply)
|
60
|
+
conversation.finalize(reply, connection)
|
60
61
|
end
|
61
62
|
end
|
62
63
|
end
|
@@ -37,31 +37,28 @@ module Mongo
|
|
37
37
|
# Finalize the PLAIN conversation. This is meant to be iterated until
|
38
38
|
# the provided reply indicates the conversation is finished.
|
39
39
|
#
|
40
|
-
# @example Finalize the conversation.
|
41
|
-
# conversation.finalize(reply)
|
42
|
-
#
|
43
40
|
# @param [ Protocol::Message ] reply The reply of the previous
|
44
41
|
# message.
|
42
|
+
# @param [ Server::Connection ] connection The connection being
|
43
|
+
# authenticated.
|
45
44
|
#
|
46
45
|
# @return [ Protocol::Query ] The next message to send.
|
47
46
|
#
|
48
47
|
# @since 2.0.0
|
49
|
-
def finalize(reply)
|
50
|
-
validate!(reply)
|
48
|
+
def finalize(reply, connection)
|
49
|
+
validate!(reply, connection.server)
|
51
50
|
end
|
52
51
|
|
53
52
|
# Start the PLAIN conversation. This returns the first message that
|
54
53
|
# needs to be sent to the server.
|
55
54
|
#
|
56
|
-
# @
|
57
|
-
#
|
58
|
-
#
|
59
|
-
# @param [ Mongo::Server::Connection ] connection The connection being authenticated.
|
55
|
+
# @param [ Server::Connection ] connection The connection being
|
56
|
+
# authenticated.
|
60
57
|
#
|
61
58
|
# @return [ Protocol::Query ] The first PLAIN conversation message.
|
62
59
|
#
|
63
60
|
# @since 2.0.0
|
64
|
-
def start(connection
|
61
|
+
def start(connection)
|
65
62
|
if connection && connection.features.op_msg_enabled?
|
66
63
|
selector = LOGIN.merge(payload: payload, mechanism: LDAP::MECHANISM)
|
67
64
|
selector[Protocol::Msg::DATABASE_IDENTIFIER] = Auth::EXTERNAL
|
@@ -96,9 +93,9 @@ module Mongo
|
|
96
93
|
BSON::Binary.new("\x00#{user.name}\x00#{user.password}")
|
97
94
|
end
|
98
95
|
|
99
|
-
def validate!(reply)
|
96
|
+
def validate!(reply, server)
|
100
97
|
if reply.documents[0][Operation::Result::OK] != 1
|
101
|
-
raise Unauthorized.new(user, used_mechanism: MECHANISM)
|
98
|
+
raise Unauthorized.new(user, used_mechanism: MECHANISM, server: server)
|
102
99
|
end
|
103
100
|
@reply = reply
|
104
101
|
end
|
data/lib/mongo/auth/scram.rb
CHANGED
@@ -20,6 +20,7 @@ module Mongo
|
|
20
20
|
# the client and server.
|
21
21
|
#
|
22
22
|
# @since 2.0.0
|
23
|
+
# @api private
|
23
24
|
class Conversation
|
24
25
|
|
25
26
|
# The base client continue message.
|
@@ -103,13 +104,14 @@ module Mongo
|
|
103
104
|
#
|
104
105
|
# @param [ Protocol::Message ] reply The reply of the previous
|
105
106
|
# message.
|
106
|
-
# @param [
|
107
|
+
# @param [ Server::Connection ] connection The connection being
|
108
|
+
# authenticated.
|
107
109
|
#
|
108
|
-
# @return [ Protocol::
|
110
|
+
# @return [ Protocol::Message ] The next message to send.
|
109
111
|
#
|
110
112
|
# @since 2.0.0
|
111
|
-
def continue(reply, connection
|
112
|
-
validate_first_message!(reply)
|
113
|
+
def continue(reply, connection)
|
114
|
+
validate_first_message!(reply, connection.server)
|
113
115
|
|
114
116
|
# The salted password needs to be calculated now; otherwise, if the
|
115
117
|
# client key is cached from a previous authentication, the salt in the
|
@@ -118,7 +120,10 @@ module Mongo
|
|
118
120
|
salted_password
|
119
121
|
|
120
122
|
if connection && connection.features.op_msg_enabled?
|
121
|
-
selector = CLIENT_CONTINUE_MESSAGE.merge(
|
123
|
+
selector = CLIENT_CONTINUE_MESSAGE.merge(
|
124
|
+
payload: client_final_message,
|
125
|
+
conversationId: id,
|
126
|
+
)
|
122
127
|
selector[Protocol::Msg::DATABASE_IDENTIFIER] = user.auth_source
|
123
128
|
cluster_time = connection.mongos? && connection.cluster_time
|
124
129
|
selector[Operation::CLUSTER_TIME] = cluster_time if cluster_time
|
@@ -127,8 +132,11 @@ module Mongo
|
|
127
132
|
Protocol::Query.new(
|
128
133
|
user.auth_source,
|
129
134
|
Database::COMMAND,
|
130
|
-
CLIENT_CONTINUE_MESSAGE.merge(
|
131
|
-
|
135
|
+
CLIENT_CONTINUE_MESSAGE.merge(
|
136
|
+
payload: client_final_message,
|
137
|
+
conversationId: id,
|
138
|
+
),
|
139
|
+
limit: -1,
|
132
140
|
)
|
133
141
|
end
|
134
142
|
end
|
@@ -136,20 +144,20 @@ module Mongo
|
|
136
144
|
# Finalize the SCRAM conversation. This is meant to be iterated until
|
137
145
|
# the provided reply indicates the conversation is finished.
|
138
146
|
#
|
139
|
-
# @example Finalize the conversation.
|
140
|
-
# conversation.finalize(reply)
|
141
|
-
#
|
142
147
|
# @param [ Protocol::Message ] reply The reply of the previous
|
143
148
|
# message.
|
144
|
-
# @param [
|
149
|
+
# @param [ Server::Connection ] connection The connection being authenticated.
|
145
150
|
#
|
146
151
|
# @return [ Protocol::Query ] The next message to send.
|
147
152
|
#
|
148
153
|
# @since 2.0.0
|
149
|
-
def finalize(reply, connection
|
150
|
-
validate_final_message!(reply)
|
154
|
+
def finalize(reply, connection)
|
155
|
+
validate_final_message!(reply, connection.server)
|
151
156
|
if connection && connection.features.op_msg_enabled?
|
152
|
-
selector = CLIENT_CONTINUE_MESSAGE.merge(
|
157
|
+
selector = CLIENT_CONTINUE_MESSAGE.merge(
|
158
|
+
payload: client_empty_message,
|
159
|
+
conversationId: id,
|
160
|
+
)
|
153
161
|
selector[Protocol::Msg::DATABASE_IDENTIFIER] = user.auth_source
|
154
162
|
cluster_time = connection.mongos? && connection.cluster_time
|
155
163
|
selector[Operation::CLUSTER_TIME] = cluster_time if cluster_time
|
@@ -158,8 +166,11 @@ module Mongo
|
|
158
166
|
Protocol::Query.new(
|
159
167
|
user.auth_source,
|
160
168
|
Database::COMMAND,
|
161
|
-
CLIENT_CONTINUE_MESSAGE.merge(
|
162
|
-
|
169
|
+
CLIENT_CONTINUE_MESSAGE.merge(
|
170
|
+
payload: client_empty_message,
|
171
|
+
conversationId: id,
|
172
|
+
),
|
173
|
+
limit: -1,
|
163
174
|
)
|
164
175
|
end
|
165
176
|
end
|
@@ -167,15 +178,12 @@ module Mongo
|
|
167
178
|
# Start the SCRAM conversation. This returns the first message that
|
168
179
|
# needs to be sent to the server.
|
169
180
|
#
|
170
|
-
# @
|
171
|
-
# conversation.start
|
172
|
-
#
|
173
|
-
# @param [ Mongo::Server::Connection ] connection The connection being authenticated.
|
181
|
+
# @param [ Server::Connection ] connection The connection being authenticated.
|
174
182
|
#
|
175
183
|
# @return [ Protocol::Query ] The first SCRAM conversation message.
|
176
184
|
#
|
177
185
|
# @since 2.0.0
|
178
|
-
def start(connection
|
186
|
+
def start(connection)
|
179
187
|
if connection && connection.features.op_msg_enabled?
|
180
188
|
selector = CLIENT_FIRST_MESSAGE.merge(
|
181
189
|
payload: client_first_message, mechanism: full_mechanism)
|
@@ -189,7 +197,7 @@ module Mongo
|
|
189
197
|
Database::COMMAND,
|
190
198
|
CLIENT_FIRST_MESSAGE.merge(
|
191
199
|
payload: client_first_message, mechanism: full_mechanism),
|
192
|
-
limit: -1
|
200
|
+
limit: -1,
|
193
201
|
)
|
194
202
|
end
|
195
203
|
end
|
@@ -505,23 +513,24 @@ module Mongo
|
|
505
513
|
check == 0
|
506
514
|
end
|
507
515
|
|
508
|
-
def validate_final_message!(reply)
|
509
|
-
validate!(reply)
|
516
|
+
def validate_final_message!(reply, server)
|
517
|
+
validate!(reply, server)
|
510
518
|
unless compare_digest(verifier, server_signature)
|
511
519
|
raise Error::InvalidSignature.new(verifier, server_signature)
|
512
520
|
end
|
513
521
|
end
|
514
522
|
|
515
|
-
def validate_first_message!(reply)
|
516
|
-
validate!(reply)
|
523
|
+
def validate_first_message!(reply, server)
|
524
|
+
validate!(reply, server)
|
517
525
|
raise Error::InvalidNonce.new(nonce, rnonce) unless rnonce.start_with?(nonce)
|
518
526
|
end
|
519
527
|
|
520
|
-
def validate!(reply)
|
528
|
+
def validate!(reply, server)
|
521
529
|
if reply.documents[0][Operation::Result::OK] != 1
|
522
530
|
raise Unauthorized.new(user,
|
523
531
|
used_mechanism: full_mechanism,
|
524
532
|
message: reply.documents[0]['errmsg'],
|
533
|
+
server: server,
|
525
534
|
)
|
526
535
|
end
|
527
536
|
@reply = reply
|