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.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/Rakefile +24 -0
  5. data/lib/mongo/address.rb +53 -37
  6. data/lib/mongo/auth.rb +30 -10
  7. data/lib/mongo/auth/cr.rb +1 -0
  8. data/lib/mongo/auth/cr/conversation.rb +13 -13
  9. data/lib/mongo/auth/ldap.rb +2 -1
  10. data/lib/mongo/auth/ldap/conversation.rb +9 -12
  11. data/lib/mongo/auth/scram.rb +1 -0
  12. data/lib/mongo/auth/scram/conversation.rb +36 -27
  13. data/lib/mongo/auth/user.rb +7 -1
  14. data/lib/mongo/auth/x509.rb +2 -1
  15. data/lib/mongo/auth/x509/conversation.rb +9 -9
  16. data/lib/mongo/bulk_write/transformable.rb +3 -3
  17. data/lib/mongo/client.rb +17 -6
  18. data/lib/mongo/cluster.rb +67 -49
  19. data/lib/mongo/cluster/sdam_flow.rb +87 -3
  20. data/lib/mongo/collection/view/readable.rb +3 -1
  21. data/lib/mongo/collection/view/writable.rb +3 -3
  22. data/lib/mongo/cursor/builder/kill_cursors_command.rb +8 -1
  23. data/lib/mongo/cursor/builder/op_kill_cursors.rb +8 -1
  24. data/lib/mongo/database.rb +1 -1
  25. data/lib/mongo/grid/file.rb +5 -0
  26. data/lib/mongo/grid/file/chunk.rb +2 -0
  27. data/lib/mongo/grid/fs_bucket.rb +15 -13
  28. data/lib/mongo/grid/stream/write.rb +9 -3
  29. data/lib/mongo/protocol/serializers.rb +12 -2
  30. data/lib/mongo/retryable.rb +33 -8
  31. data/lib/mongo/server.rb +13 -6
  32. data/lib/mongo/server/connection.rb +15 -8
  33. data/lib/mongo/server/connection_base.rb +7 -4
  34. data/lib/mongo/server/description.rb +34 -21
  35. data/lib/mongo/server/monitor.rb +1 -1
  36. data/lib/mongo/server/monitor/connection.rb +2 -3
  37. data/lib/mongo/session.rb +10 -10
  38. data/lib/mongo/socket.rb +10 -1
  39. data/lib/mongo/uri.rb +1 -1
  40. data/lib/mongo/version.rb +1 -1
  41. data/mongo.gemspec +1 -1
  42. data/spec/README.md +13 -0
  43. data/spec/integration/auth_spec.rb +27 -8
  44. data/spec/integration/bson_symbol_spec.rb +34 -0
  45. data/spec/integration/client_construction_spec.rb +14 -0
  46. data/spec/integration/client_options_spec.rb +5 -5
  47. data/spec/integration/connection_spec.rb +57 -9
  48. data/spec/integration/crud_spec.rb +45 -0
  49. data/spec/integration/cursor_reaping_spec.rb +2 -1
  50. data/spec/integration/grid_fs_bucket_spec.rb +48 -0
  51. data/spec/integration/retryable_errors_spec.rb +204 -39
  52. data/spec/integration/retryable_writes_spec.rb +36 -36
  53. data/spec/integration/size_limit_spec.rb~12e1e9c4f... RUBY-2242 Fix zlib compression (#2021) +98 -0
  54. data/spec/lite_spec_helper.rb +1 -0
  55. data/spec/mongo/address_spec.rb +19 -13
  56. data/spec/mongo/auth/ldap/conversation_spec.rb +1 -1
  57. data/spec/mongo/auth/scram/conversation_spec.rb +25 -14
  58. data/spec/mongo/auth/user/view_spec.rb +36 -1
  59. data/spec/mongo/auth/user_spec.rb +12 -0
  60. data/spec/mongo/auth/x509/conversation_spec.rb +1 -1
  61. data/spec/mongo/bulk_write_spec.rb +2 -2
  62. data/spec/mongo/client_construction_spec.rb +1 -21
  63. data/spec/mongo/cluster_spec.rb +57 -0
  64. data/spec/mongo/collection/view/map_reduce_spec.rb +1 -1
  65. data/spec/mongo/collection_spec.rb +26 -2
  66. data/spec/mongo/cursor/builder/op_kill_cursors_spec.rb +56 -0
  67. data/spec/mongo/server/connection_spec.rb +76 -8
  68. data/spec/mongo/server/monitor/connection_spec.rb +14 -7
  69. data/spec/mongo/socket/ssl_spec.rb +132 -98
  70. data/spec/mongo/socket/tcp_spec.rb +1 -9
  71. data/spec/mongo/uri_spec.rb +1 -1
  72. data/spec/runners/sdam/verifier.rb +91 -0
  73. data/spec/spec_tests/data/sdam/rs/primary_address_change.yml +29 -0
  74. data/spec/spec_tests/data/sdam/rs/primary_mismatched_me.yml +27 -23
  75. data/spec/spec_tests/data/sdam/rs/primary_to_no_primary_mismatched_me.yml +56 -79
  76. data/spec/spec_tests/data/sdam/sharded/primary_address_change.yml +21 -0
  77. data/spec/spec_tests/data/sdam/sharded/primary_mismatched_me.yml +22 -0
  78. data/spec/spec_tests/data/sdam/single/primary_address_change.yml +24 -0
  79. data/spec/spec_tests/data/sdam/single/primary_mismatched_me.yml +25 -0
  80. data/spec/spec_tests/data/sdam_monitoring/replica_set_with_me_mismatch.yml +159 -0
  81. data/spec/spec_tests/data/sdam_monitoring/{replica_set_other_seed.yml → replica_set_with_primary_change.yml} +97 -101
  82. data/spec/spec_tests/data/sdam_monitoring/replica_set_with_primary_removal.yml +22 -18
  83. data/spec/spec_tests/data/sdam_monitoring/standalone_to_rs_with_me_mismatch.yml +90 -0
  84. data/spec/spec_tests/sdam_monitoring_spec.rb +9 -4
  85. data/spec/support/cluster_config.rb +36 -0
  86. data/spec/support/cluster_tools.rb +5 -3
  87. data/spec/support/command_monitoring.rb +1 -1
  88. data/spec/support/constraints.rb +18 -18
  89. data/spec/support/lite_constraints.rb +8 -0
  90. data/spec/support/sdam_monitoring.rb +0 -115
  91. data/spec/support/server_discovery_and_monitoring.rb +2 -0
  92. data/spec/support/spec_config.rb +1 -1
  93. data/spec/support/utils.rb +11 -1
  94. metadata +687 -659
  95. metadata.gz.sig +3 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d27047092172489df2f36b02e09050990a7aae2685a055bf4a30d33a43b86325
4
- data.tar.gz: 0f14e016a1dbae9ccda55d77927a773d58a10967b959b9480b052c2df9410386
3
+ metadata.gz: 8c345d3cf6aa92723002548f8e1e14be65bdfb0969eb05756d510f51a7a6b4ec
4
+ data.tar.gz: 306c19eafbaee190b5f865beedc5a149b46c5d45aeae509f85390c6e554c25e2
5
5
  SHA512:
6
- metadata.gz: 3cf2e4bfd5860003b7131c72fae1b58a0a56906a73d67e9e08c465cd5cf0b79f99af431e55597733f3baf9d68a9617cec47647d4bb7b9c8e84eedeeff96509b9
7
- data.tar.gz: 190be385cbcfdae0293448281010b8d6c4ca785b37236fe57362921eaeb7cfdb5115dd0159e51622946b97170fa105a375fd0a73ceb4600b268e599aa687dcf1
6
+ metadata.gz: 80389668e920fe61e0aedad8ae4bf6973cc3f3f150a7e6a49514aee5aec7e062e00851abcabd273efacffc2c080373d0036cc74e49f3fab8607ab133f901e1b8
7
+ data.tar.gz: 41c28e98cef6df75eb38e4a043c3c4bfce8623a3f68a10522a02d22984a31d0283af5113d8dd8c4ba37aa7df373ff400a9a1359acb9731c1a433c370976b2aa7
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')
@@ -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 provided address, given the options.
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
- # The address the socket connects to is determined by the algorithm described in the
144
- # #intialize_resolver! documentation. Each time this method is called, #initialize_resolver!
145
- # will be called, meaning that a new hostname lookup will occur. This is done so that any
146
- # changes to which addresses the hostname resolves to will be picked up even if a socket has
147
- # been connected to it before.
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, Mongo::Socket::TCP, Mongo::Socket::Unix ] The socket.
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
- create_resolver(ssl_options).socket(socket_timeout, ssl_options, options)
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
@@ -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
- specified_mechanism = if user.mechanism
117
- " (mechanism: #{user.mechanism})"
118
- else
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
- used_mechanism = if used_mechanism
122
- " (used mechanism: #{used_mechanism})"
123
- else
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
- msg = "#{used_user}#{specified_mechanism} is not authorized to access #{user.database} (auth source: #{user.auth_source})#{used_mechanism}"
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
@@ -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 authenticated.
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 = nil)
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 = nil)
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
- # @example Start the conversation.
98
- # conversation.start
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 = nil)
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
@@ -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
- # @example Start the conversation.
57
- # conversation.start
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 = nil)
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
@@ -20,6 +20,7 @@ module Mongo
20
20
  # Defines behavior for SCRAM authentication.
21
21
  #
22
22
  # @since 2.0.0
23
+ # @api private
23
24
  class SCRAM
24
25
 
25
26
  # The authentication mechanism string for SCRAM-SHA-1.
@@ -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 [ Mongo::Server::Connection ] connection The connection being authenticated.
107
+ # @param [ Server::Connection ] connection The connection being
108
+ # authenticated.
107
109
  #
108
- # @return [ Protocol::Query ] The next message to send.
110
+ # @return [ Protocol::Message ] The next message to send.
109
111
  #
110
112
  # @since 2.0.0
111
- def continue(reply, connection = nil)
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(payload: client_final_message, conversationId: id)
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(payload: client_final_message, conversationId: id),
131
- limit: -1
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 [ Mongo::Server::Connection ] connection The connection being authenticated.
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 = nil)
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(payload: client_empty_message, conversationId: id)
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(payload: client_empty_message, conversationId: id),
162
- limit: -1
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
- # @example Start the conversation.
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 = nil)
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