mongo 2.11.4 → 2.12.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (357) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/CONTRIBUTING.md +1 -1
  5. data/README.md +2 -1
  6. data/lib/mongo.rb +3 -0
  7. data/lib/mongo/address.rb +44 -19
  8. data/lib/mongo/auth.rb +1 -0
  9. data/lib/mongo/auth/credential_cache.rb +51 -0
  10. data/lib/mongo/auth/scram/conversation.rb +20 -16
  11. data/lib/mongo/auth/user.rb +0 -8
  12. data/lib/mongo/auth/user/view.rb +4 -4
  13. data/lib/mongo/background_thread.rb +1 -1
  14. data/lib/mongo/bulk_write.rb +5 -5
  15. data/lib/mongo/client.rb +143 -14
  16. data/lib/mongo/client_encryption.rb +103 -0
  17. data/lib/mongo/cluster.rb +8 -4
  18. data/lib/mongo/cluster/reapers/cursor_reaper.rb +18 -6
  19. data/lib/mongo/cluster/sdam_flow.rb +54 -58
  20. data/lib/mongo/collection.rb +3 -3
  21. data/lib/mongo/collection/view.rb +1 -1
  22. data/lib/mongo/collection/view/aggregation.rb +1 -1
  23. data/lib/mongo/collection/view/change_stream.rb +12 -3
  24. data/lib/mongo/collection/view/iterable.rb +14 -5
  25. data/lib/mongo/collection/view/map_reduce.rb +2 -2
  26. data/lib/mongo/collection/view/readable.rb +9 -7
  27. data/lib/mongo/collection/view/writable.rb +7 -7
  28. data/lib/mongo/crypt.rb +33 -0
  29. data/lib/mongo/crypt/auto_decryption_context.rb +40 -0
  30. data/lib/mongo/crypt/auto_encrypter.rb +179 -0
  31. data/lib/mongo/crypt/auto_encryption_context.rb +44 -0
  32. data/lib/mongo/crypt/binary.rb +155 -0
  33. data/lib/mongo/crypt/binding.rb +1229 -0
  34. data/lib/mongo/crypt/context.rb +135 -0
  35. data/lib/mongo/crypt/data_key_context.rb +162 -0
  36. data/lib/mongo/crypt/encryption_io.rb +289 -0
  37. data/lib/mongo/crypt/explicit_decryption_context.rb +40 -0
  38. data/lib/mongo/crypt/explicit_encrypter.rb +117 -0
  39. data/lib/mongo/crypt/explicit_encryption_context.rb +89 -0
  40. data/lib/mongo/crypt/handle.rb +315 -0
  41. data/lib/mongo/crypt/hooks.rb +90 -0
  42. data/lib/mongo/crypt/kms_context.rb +67 -0
  43. data/lib/mongo/crypt/status.rb +131 -0
  44. data/lib/mongo/cursor.rb +64 -32
  45. data/lib/mongo/database.rb +23 -6
  46. data/lib/mongo/database/view.rb +13 -4
  47. data/lib/mongo/dbref.rb +9 -2
  48. data/lib/mongo/error.rb +5 -1
  49. data/lib/mongo/error/bulk_write_error.rb +16 -14
  50. data/lib/mongo/error/crypt_error.rb +31 -0
  51. data/lib/mongo/error/{failed_stringprep_validation.rb → failed_string_prep_validation.rb} +0 -0
  52. data/lib/mongo/error/invalid_cursor_operation.rb +27 -0
  53. data/lib/mongo/error/kms_error.rb +22 -0
  54. data/lib/mongo/error/max_bson_size.rb +14 -3
  55. data/lib/mongo/error/mongocryptd_spawn_error.rb +22 -0
  56. data/lib/mongo/error/no_server_available.rb +8 -3
  57. data/lib/mongo/error/notable.rb +0 -15
  58. data/lib/mongo/error/operation_failure.rb +1 -0
  59. data/lib/mongo/error/parser.rb +1 -1
  60. data/lib/mongo/grid/file.rb +5 -0
  61. data/lib/mongo/grid/file/chunk.rb +2 -0
  62. data/lib/mongo/grid/file/info.rb +3 -2
  63. data/lib/mongo/grid/fs_bucket.rb +15 -13
  64. data/lib/mongo/grid/stream/write.rb +9 -3
  65. data/lib/mongo/index/view.rb +3 -3
  66. data/lib/mongo/monitoring/event/cmap/connection_check_out_failed.rb +1 -1
  67. data/lib/mongo/monitoring/event/command_started.rb +6 -1
  68. data/lib/mongo/operation/collections_info.rb +6 -3
  69. data/lib/mongo/operation/delete/op_msg.rb +1 -1
  70. data/lib/mongo/operation/find/op_msg.rb +4 -1
  71. data/lib/mongo/operation/get_more/op_msg.rb +4 -1
  72. data/lib/mongo/operation/insert/command.rb +3 -2
  73. data/lib/mongo/operation/insert/legacy.rb +3 -2
  74. data/lib/mongo/operation/insert/op_msg.rb +3 -3
  75. data/lib/mongo/operation/result.rb +36 -27
  76. data/lib/mongo/operation/shared/executable.rb +11 -9
  77. data/lib/mongo/operation/shared/executable_no_validate.rb +2 -2
  78. data/lib/mongo/operation/shared/op_msg_or_command.rb +2 -2
  79. data/lib/mongo/operation/shared/op_msg_or_find_command.rb +2 -2
  80. data/lib/mongo/operation/shared/op_msg_or_list_indexes_command.rb +2 -2
  81. data/lib/mongo/operation/shared/read_preference_supported.rb +68 -19
  82. data/lib/mongo/operation/shared/response_handling.rb +1 -1
  83. data/lib/mongo/operation/shared/sessions_supported.rb +44 -3
  84. data/lib/mongo/operation/shared/write.rb +17 -10
  85. data/lib/mongo/operation/update/op_msg.rb +1 -1
  86. data/lib/mongo/protocol/bit_vector.rb +2 -1
  87. data/lib/mongo/protocol/compressed.rb +6 -5
  88. data/lib/mongo/protocol/insert.rb +3 -1
  89. data/lib/mongo/protocol/message.rb +94 -15
  90. data/lib/mongo/protocol/msg.rb +207 -37
  91. data/lib/mongo/protocol/query.rb +7 -9
  92. data/lib/mongo/protocol/serializers.rb +43 -15
  93. data/lib/mongo/retryable.rb +1 -1
  94. data/lib/mongo/server.rb +10 -4
  95. data/lib/mongo/server/connection.rb +20 -9
  96. data/lib/mongo/server/connection_base.rb +118 -18
  97. data/lib/mongo/server/connection_common.rb +61 -0
  98. data/lib/mongo/server/connection_pool.rb +37 -1
  99. data/lib/mongo/server/connection_pool/populator.rb +1 -1
  100. data/lib/mongo/server/description.rb +9 -11
  101. data/lib/mongo/server/monitor.rb +2 -0
  102. data/lib/mongo/server/monitor/connection.rb +3 -18
  103. data/lib/mongo/server/pending_connection.rb +2 -1
  104. data/lib/mongo/session.rb +3 -3
  105. data/lib/mongo/session/session_pool.rb +8 -3
  106. data/lib/mongo/socket.rb +29 -16
  107. data/lib/mongo/socket/ssl.rb +23 -8
  108. data/lib/mongo/socket/tcp.rb +12 -3
  109. data/lib/mongo/srv/monitor.rb +73 -42
  110. data/lib/mongo/srv/result.rb +0 -1
  111. data/lib/mongo/timeout.rb +49 -0
  112. data/lib/mongo/uri.rb +30 -1
  113. data/lib/mongo/uri/srv_protocol.rb +1 -1
  114. data/lib/mongo/version.rb +1 -1
  115. data/mongo.gemspec +1 -3
  116. data/spec/README.md +228 -7
  117. data/spec/integration/auth_spec.rb +53 -0
  118. data/spec/integration/bulk_write_spec.rb +19 -0
  119. data/spec/integration/{client_options_spec.rb → client_authentication_options_spec.rb} +10 -10
  120. data/spec/integration/client_construction_spec.rb +100 -1
  121. data/spec/integration/client_side_encryption/auto_encryption_bulk_writes_spec.rb +353 -0
  122. data/spec/integration/client_side_encryption/auto_encryption_command_monitoring_spec.rb +303 -0
  123. data/spec/integration/client_side_encryption/auto_encryption_mongocryptd_spawn_spec.rb +72 -0
  124. data/spec/integration/client_side_encryption/auto_encryption_old_wire_version_spec.rb +79 -0
  125. data/spec/integration/client_side_encryption/auto_encryption_reconnect_spec.rb +221 -0
  126. data/spec/integration/client_side_encryption/auto_encryption_spec.rb +601 -0
  127. data/spec/integration/client_side_encryption/bson_size_limit_spec.rb +187 -0
  128. data/spec/integration/client_side_encryption/bypass_mongocryptd_spawn_spec.rb +78 -0
  129. data/spec/integration/client_side_encryption/client_close_spec.rb +63 -0
  130. data/spec/integration/client_side_encryption/corpus_spec.rb +233 -0
  131. data/spec/integration/client_side_encryption/custom_endpoint_spec.rb +132 -0
  132. data/spec/integration/client_side_encryption/data_key_spec.rb +165 -0
  133. data/spec/integration/client_side_encryption/explicit_encryption_spec.rb +114 -0
  134. data/spec/integration/client_side_encryption/external_key_vault_spec.rb +141 -0
  135. data/spec/integration/client_side_encryption/views_spec.rb +44 -0
  136. data/spec/integration/client_update_spec.rb +154 -0
  137. data/spec/integration/command_monitoring_spec.rb +3 -1
  138. data/spec/integration/command_spec.rb +44 -10
  139. data/spec/integration/connection_spec.rb +57 -0
  140. data/spec/integration/crud_spec.rb +89 -0
  141. data/spec/integration/grid_fs_bucket_spec.rb +48 -0
  142. data/spec/integration/read_preference_spec.rb +26 -0
  143. data/spec/integration/reconnect_spec.rb +7 -6
  144. data/spec/integration/size_limit_spec.rb +111 -0
  145. data/spec/integration/srv_monitoring_spec.rb +16 -8
  146. data/spec/integration/zlib_compression_spec.rb +25 -0
  147. data/spec/kerberos/kerberos_spec.rb +87 -0
  148. data/spec/lite_spec_helper.rb +34 -29
  149. data/spec/mongo/auth/cr_spec.rb +8 -0
  150. data/spec/mongo/auth/ldap_spec.rb +5 -1
  151. data/spec/mongo/auth/scram/conversation_spec.rb +5 -6
  152. data/spec/mongo/auth/scram/negotiation_spec.rb +74 -75
  153. data/spec/mongo/auth/scram_spec.rb +45 -35
  154. data/spec/mongo/auth/user/view_spec.rb +3 -6
  155. data/spec/mongo/auth/x509_spec.rb +5 -1
  156. data/spec/mongo/bulk_write/result_spec.rb +11 -7
  157. data/spec/mongo/client_construction_spec.rb +206 -2
  158. data/spec/mongo/client_encryption_spec.rb +405 -0
  159. data/spec/mongo/cluster/cursor_reaper_spec.rb +12 -8
  160. data/spec/mongo/cluster/socket_reaper_spec.rb +14 -3
  161. data/spec/mongo/collection/view/aggregation_spec.rb +0 -2
  162. data/spec/mongo/collection/view/change_stream_spec.rb +7 -7
  163. data/spec/mongo/collection/view/map_reduce_spec.rb +3 -3
  164. data/spec/mongo/collection/view_spec.rb +1 -1
  165. data/spec/mongo/collection_spec.rb +28 -9
  166. data/spec/mongo/crypt/auto_decryption_context_spec.rb +90 -0
  167. data/spec/mongo/crypt/auto_encrypter_spec.rb +187 -0
  168. data/spec/mongo/crypt/auto_encryption_context_spec.rb +107 -0
  169. data/spec/mongo/crypt/binary_spec.rb +115 -0
  170. data/spec/mongo/crypt/binding/binary_spec.rb +56 -0
  171. data/spec/mongo/crypt/binding/context_spec.rb +257 -0
  172. data/spec/mongo/crypt/binding/helpers_spec.rb +46 -0
  173. data/spec/mongo/crypt/binding/mongocrypt_spec.rb +144 -0
  174. data/spec/mongo/crypt/binding/status_spec.rb +99 -0
  175. data/spec/mongo/crypt/binding/version_spec.rb +22 -0
  176. data/spec/mongo/crypt/binding_unloaded_spec.rb +20 -0
  177. data/spec/mongo/crypt/data_key_context_spec.rb +213 -0
  178. data/spec/mongo/crypt/encryption_io_spec.rb +136 -0
  179. data/spec/mongo/crypt/explicit_decryption_context_spec.rb +72 -0
  180. data/spec/mongo/crypt/explicit_encryption_context_spec.rb +170 -0
  181. data/spec/mongo/crypt/handle_spec.rb +232 -0
  182. data/spec/mongo/crypt/helpers/mongo_crypt_spec_helper.rb +108 -0
  183. data/spec/mongo/crypt/status_spec.rb +152 -0
  184. data/spec/mongo/cursor_spec.rb +24 -4
  185. data/spec/mongo/database_spec.rb +20 -0
  186. data/spec/mongo/error/bulk_write_error_spec.rb +49 -0
  187. data/spec/mongo/error/crypt_error_spec.rb +26 -0
  188. data/spec/mongo/error/max_bson_size_spec.rb +35 -0
  189. data/spec/mongo/error/no_server_available_spec.rb +11 -1
  190. data/spec/mongo/error/notable_spec.rb +59 -0
  191. data/spec/mongo/error/operation_failure_spec.rb +6 -6
  192. data/spec/mongo/operation/aggregate_spec.rb +1 -1
  193. data/spec/mongo/operation/collections_info_spec.rb +1 -1
  194. data/spec/mongo/operation/command_spec.rb +3 -3
  195. data/spec/mongo/operation/create_index_spec.rb +3 -3
  196. data/spec/mongo/operation/create_user_spec.rb +3 -3
  197. data/spec/mongo/operation/delete/bulk_spec.rb +6 -6
  198. data/spec/mongo/operation/delete/op_msg_spec.rb +1 -6
  199. data/spec/mongo/operation/delete_spec.rb +7 -7
  200. data/spec/mongo/operation/drop_index_spec.rb +2 -2
  201. data/spec/mongo/operation/find/legacy_spec.rb +2 -1
  202. data/spec/mongo/operation/get_more_spec.rb +1 -1
  203. data/spec/mongo/operation/indexes_spec.rb +1 -1
  204. data/spec/mongo/operation/insert/bulk_spec.rb +7 -7
  205. data/spec/mongo/operation/insert/op_msg_spec.rb +3 -6
  206. data/spec/mongo/operation/insert_spec.rb +12 -12
  207. data/spec/mongo/operation/map_reduce_spec.rb +2 -2
  208. data/spec/mongo/operation/read_preference_legacy_spec.rb +351 -0
  209. data/spec/mongo/operation/read_preference_op_msg_spec.rb +194 -0
  210. data/spec/mongo/operation/remove_user_spec.rb +3 -3
  211. data/spec/mongo/operation/update/bulk_spec.rb +6 -6
  212. data/spec/mongo/operation/update/op_msg_spec.rb +3 -6
  213. data/spec/mongo/operation/update_spec.rb +7 -7
  214. data/spec/mongo/operation/update_user_spec.rb +1 -1
  215. data/spec/mongo/protocol/compressed_spec.rb +2 -3
  216. data/spec/mongo/protocol/delete_spec.rb +9 -8
  217. data/spec/mongo/protocol/get_more_spec.rb +9 -8
  218. data/spec/mongo/protocol/insert_spec.rb +9 -8
  219. data/spec/mongo/protocol/kill_cursors_spec.rb +6 -5
  220. data/spec/mongo/protocol/msg_spec.rb +57 -53
  221. data/spec/mongo/protocol/query_spec.rb +12 -12
  222. data/spec/mongo/protocol/registry_spec.rb +1 -1
  223. data/spec/mongo/protocol/reply_spec.rb +1 -1
  224. data/spec/mongo/protocol/update_spec.rb +10 -9
  225. data/spec/mongo/server/connection_pool_spec.rb +1 -1
  226. data/spec/mongo/server/connection_spec.rb +28 -7
  227. data/spec/mongo/socket_spec.rb +1 -1
  228. data/spec/mongo/srv/monitor_spec.rb +88 -69
  229. data/spec/mongo/timeout_spec.rb +85 -0
  230. data/spec/mongo/uri/srv_protocol_spec.rb +2 -2
  231. data/spec/mongo/uri_spec.rb +52 -5
  232. data/spec/mongo/write_concern_spec.rb +13 -1
  233. data/spec/{support → runners}/auth.rb +14 -1
  234. data/spec/{support → runners}/change_streams.rb +1 -1
  235. data/spec/{support → runners}/change_streams/operation.rb +0 -0
  236. data/spec/{support → runners}/cmap.rb +1 -1
  237. data/spec/{support → runners}/cmap/verifier.rb +0 -0
  238. data/spec/{support → runners}/command_monitoring.rb +0 -0
  239. data/spec/runners/connection_string.rb +358 -4
  240. data/spec/{support → runners}/crud.rb +9 -9
  241. data/spec/{support → runners}/crud/context.rb +0 -0
  242. data/spec/{support → runners}/crud/operation.rb +7 -3
  243. data/spec/{support → runners}/crud/outcome.rb +0 -0
  244. data/spec/{support → runners}/crud/requirement.rb +1 -1
  245. data/spec/{support → runners}/crud/spec.rb +12 -1
  246. data/spec/{support → runners}/crud/test.rb +0 -0
  247. data/spec/{support → runners}/crud/test_base.rb +0 -0
  248. data/spec/{support → runners}/crud/verifier.rb +10 -12
  249. data/spec/{support → runners}/gridfs.rb +0 -0
  250. data/spec/{support → runners}/sdam_monitoring.rb +0 -0
  251. data/spec/{support → runners}/server_discovery_and_monitoring.rb +0 -0
  252. data/spec/{support → runners}/server_selection.rb +0 -0
  253. data/spec/{support → runners}/server_selection_rtt.rb +0 -0
  254. data/spec/{support → runners}/transactions.rb +9 -11
  255. data/spec/{support → runners}/transactions/context.rb +0 -0
  256. data/spec/{support → runners}/transactions/operation.rb +0 -0
  257. data/spec/{support → runners}/transactions/spec.rb +0 -0
  258. data/spec/{support → runners}/transactions/test.rb +37 -5
  259. data/spec/spec_helper.rb +0 -5
  260. data/spec/spec_tests/auth_spec.rb +3 -3
  261. data/spec/spec_tests/client_side_encryption_spec.rb +8 -0
  262. data/spec/spec_tests/connection_string_spec.rb +1 -1
  263. data/spec/spec_tests/data/auth/connection-string.yml +13 -0
  264. data/spec/spec_tests/data/client_side_encryption/aggregate.yml +134 -0
  265. data/spec/spec_tests/data/client_side_encryption/badQueries.yml +526 -0
  266. data/spec/spec_tests/data/client_side_encryption/badSchema.yml +73 -0
  267. data/spec/spec_tests/data/client_side_encryption/basic.yml +116 -0
  268. data/spec/spec_tests/data/client_side_encryption/bulk.yml +88 -0
  269. data/spec/spec_tests/data/client_side_encryption/bypassAutoEncryption.yml +100 -0
  270. data/spec/spec_tests/data/client_side_encryption/bypassedCommand.yml +42 -0
  271. data/spec/spec_tests/data/client_side_encryption/count.yml +61 -0
  272. data/spec/spec_tests/data/client_side_encryption/countDocuments.yml +59 -0
  273. data/spec/spec_tests/data/client_side_encryption/delete.yml +105 -0
  274. data/spec/spec_tests/data/client_side_encryption/distinct.yml +73 -0
  275. data/spec/spec_tests/data/client_side_encryption/explain.yml +64 -0
  276. data/spec/spec_tests/data/client_side_encryption/find.yml +119 -0
  277. data/spec/spec_tests/data/client_side_encryption/findOneAndDelete.yml +57 -0
  278. data/spec/spec_tests/data/client_side_encryption/findOneAndReplace.yml +57 -0
  279. data/spec/spec_tests/data/client_side_encryption/findOneAndUpdate.yml +57 -0
  280. data/spec/spec_tests/data/client_side_encryption/getMore.yml +68 -0
  281. data/spec/spec_tests/data/client_side_encryption/insert.yml +102 -0
  282. data/spec/spec_tests/data/client_side_encryption/keyAltName.yml +71 -0
  283. data/spec/spec_tests/data/client_side_encryption/localKMS.yml +54 -0
  284. data/spec/spec_tests/data/client_side_encryption/localSchema.yml +72 -0
  285. data/spec/spec_tests/data/client_side_encryption/malformedCiphertext.yml +69 -0
  286. data/spec/spec_tests/data/client_side_encryption/maxWireVersion.yml +20 -0
  287. data/spec/spec_tests/data/client_side_encryption/missingKey.yml +49 -0
  288. data/spec/spec_tests/data/client_side_encryption/replaceOne.yml +64 -0
  289. data/spec/spec_tests/data/client_side_encryption/types.yml +527 -0
  290. data/spec/spec_tests/data/client_side_encryption/unsupportedCommand.yml +25 -0
  291. data/spec/spec_tests/data/client_side_encryption/updateMany.yml +77 -0
  292. data/spec/spec_tests/data/client_side_encryption/updateOne.yml +171 -0
  293. data/spec/spec_tests/data/read_write_concern/connection-string/write-concern.yml +1 -4
  294. data/spec/spec_tests/data/retryable_writes/insertOne-serverErrors.yml +21 -0
  295. data/spec/spec_tests/data/sdam/rs/incompatible_ghost.yml +2 -4
  296. data/spec/spec_tests/data/sdam/rs/incompatible_other.yml +1 -1
  297. data/spec/spec_tests/data/sdam/rs/primary_mismatched_me_not_removed.yml +73 -0
  298. data/spec/spec_tests/data/sdam/rs/primary_to_no_primary_mismatched_me.yml +1 -2
  299. data/spec/spec_tests/data/sdam/rs/repeated.yml +101 -0
  300. data/spec/spec_tests/data/sdam/rs/{primary_address_change.yml → ruby_primary_address_change.yml} +2 -0
  301. data/spec/spec_tests/data/sdam/rs/{secondary_wrong_set_name_with_primary_second.yml → ruby_secondary_wrong_set_name_with_primary_second.yml} +0 -0
  302. data/spec/spec_tests/data/sdam/sharded/ruby_discovered_single_mongos.yml +27 -0
  303. data/spec/spec_tests/data/sdam/sharded/{primary_address_change.yml → ruby_primary_different_address.yml} +1 -1
  304. data/spec/spec_tests/data/sdam/sharded/{primary_mismatched_me.yml → ruby_primary_mismatched_me.yml} +1 -1
  305. data/spec/spec_tests/data/sdam/single/{primary_address_change.yml → ruby_primary_different_address.yml} +1 -1
  306. data/spec/spec_tests/data/sdam/single/{primary_mismatched_me.yml → ruby_primary_mismatched_me.yml} +1 -1
  307. data/spec/spec_tests/data/sdam_monitoring/{replica_set_with_primary_change.yml → replica_set_primary_address_change.yml} +27 -5
  308. data/spec/spec_tests/data/sdam_monitoring/replica_set_with_me_mismatch.yml +26 -74
  309. data/spec/spec_tests/data/sdam_monitoring/replica_set_with_removal.yml +20 -16
  310. data/spec/spec_tests/data/sdam_monitoring/standalone_suppress_equal_description_changes.yml +73 -0
  311. data/spec/spec_tests/data/transactions/pin-mongos.yml +2 -3
  312. data/spec/spec_tests/data/uri_options/auth-options.yml +10 -0
  313. data/spec/spec_tests/data/uri_options/tls-options.yml +75 -4
  314. data/spec/spec_tests/read_write_concern_connection_string_spec.rb +1 -1
  315. data/spec/spec_tests/uri_options_spec.rb +6 -8
  316. data/spec/stress/connection_pool_timing_spec.rb +6 -3
  317. data/spec/support/certificates/README.md +4 -0
  318. data/spec/support/certificates/server-second-level-bundle.pem +77 -77
  319. data/spec/support/certificates/server-second-level.crt +52 -52
  320. data/spec/support/certificates/server-second-level.key +25 -25
  321. data/spec/support/certificates/server-second-level.pem +77 -77
  322. data/spec/support/client_registry.rb +19 -3
  323. data/spec/support/cluster_config.rb +9 -1
  324. data/spec/support/cluster_tools.rb +6 -1
  325. data/spec/support/common_shortcuts.rb +12 -0
  326. data/spec/support/constraints.rb +16 -0
  327. data/spec/support/crypt.rb +154 -0
  328. data/spec/support/crypt/corpus/corpus-key-aws.json +33 -0
  329. data/spec/support/crypt/corpus/corpus-key-local.json +31 -0
  330. data/spec/support/crypt/corpus/corpus-schema.json +2057 -0
  331. data/spec/support/crypt/corpus/corpus.json +3657 -0
  332. data/spec/support/crypt/corpus/corpus_encrypted.json +4152 -0
  333. data/spec/support/crypt/data_keys/key_document_aws.json +34 -0
  334. data/spec/support/crypt/data_keys/key_document_local.json +31 -0
  335. data/spec/support/crypt/external/external-key.json +31 -0
  336. data/spec/support/crypt/external/external-schema.json +19 -0
  337. data/spec/support/crypt/limits/limits-doc.json +102 -0
  338. data/spec/support/crypt/limits/limits-key.json +31 -0
  339. data/spec/support/crypt/limits/limits-schema.json +1405 -0
  340. data/spec/support/crypt/schema_maps/schema_map_aws.json +17 -0
  341. data/spec/support/crypt/schema_maps/schema_map_aws_key_alt_names.json +12 -0
  342. data/spec/support/crypt/schema_maps/schema_map_local.json +18 -0
  343. data/spec/support/crypt/schema_maps/schema_map_local_key_alt_names.json +12 -0
  344. data/spec/support/lite_constraints.rb +19 -1
  345. data/spec/support/matchers.rb +19 -0
  346. data/spec/support/shared/protocol.rb +2 -0
  347. data/spec/support/spec_config.rb +53 -13
  348. data/spec/support/utils.rb +140 -10
  349. metadata +894 -687
  350. metadata.gz.sig +0 -0
  351. data/lib/mongo/cluster/srv_monitor.rb +0 -127
  352. data/lib/mongo/srv/warning_result.rb +0 -35
  353. data/spec/enterprise_auth/kerberos_spec.rb +0 -58
  354. data/spec/mongo/cluster/srv_monitor_spec.rb +0 -214
  355. data/spec/mongo/operation/read_preference_spec.rb +0 -245
  356. data/spec/spec_tests/data/sdam/sharded/single_mongos.yml +0 -33
  357. data/spec/support/connection_string.rb +0 -354
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d3363520c62689e2f649389acd84f68b46dba99a62d82c174c77414f66e055dd
4
- data.tar.gz: 7b1a54bcc8657047ec15b61cdf39588965fc9328d0ac56aa294f7891ef7fb3e2
3
+ metadata.gz: d246db379228f5a887c2fdc21098808da28bcfba008dd6d3218475c6d00b112e
4
+ data.tar.gz: 34be39488f7ce9de6746e03db0524d80815c12bcd384a488734572576f491eec
5
5
  SHA512:
6
- metadata.gz: 546bfab9a6042f6194f87efc8f19fa92ee9828040d1f34a98045e243cce6f056837e4144856a37803f964cf345724ccfdeb6eb2d407f265b4a02e7a14622f0a1
7
- data.tar.gz: 9eb09ae2c44b3cee7cd9c082af7702b0acd4b56674a6c17b3959c05f654987b3b34f6d87c8d74d9863f312addc01a8de090899a879847d014fa0e7c9baa217d6
6
+ metadata.gz: 1998d33cea6ea9d43e473075b737452c5dff52d0fc7af2ef02b50fa7a56e741f26161bb475e89bba1a4fdfadd31c863b337a9c8dd26bfd5d4a21ccf43a741f7d
7
+ data.tar.gz: 42aa2fc57a621849a814e2fec41a7e982927303caa4199892b970289c38a620995764c76c6848090c1d74d7af56b1b1f9c99ce12f9de44a05b3255bf510b6f3a
Binary file
data.tar.gz.sig CHANGED
Binary file
@@ -23,7 +23,7 @@ Environment
23
23
  We recommend using [rbenv](https://github.com/sstephenson/rbenv) to set up
24
24
  the Ruby development and testing environments, though other tools like
25
25
  [RVM](https://rvm.io/) will also work. The driver currently supports
26
- MRI 2.3-2.6 and JRuby 9.2.
26
+ MRI 2.3-2.7 and JRuby 9.2.
27
27
 
28
28
  A MongoDB cluster is required to run the tests. Setup procedures and
29
29
  recommendations for various clusters, as well as how to configure the
data/README.md CHANGED
@@ -18,7 +18,8 @@ Support & Feedback
18
18
  For issues, questions or feedback related to the Ruby driver, please look into
19
19
  our [support channels](http://www.mongodb.org/about/support). Please
20
20
  do not email any of the Ruby developers directly with issues or
21
- questions - you're more likely to get an answer quickly on the [mongodb-user list](http://groups.google.com/group/mongodb-user) on Google Groups.
21
+ questions - you're more likely to get an answer quickly on the
22
+ [MongoDB Community Forum](https://community.mongodb.com).
22
23
 
23
24
 
24
25
  Bugs & Feature Requests
@@ -49,6 +49,7 @@ require 'mongo/cluster'
49
49
  require 'mongo/cursor'
50
50
  require 'mongo/collection'
51
51
  require 'mongo/database'
52
+ require 'mongo/crypt'
52
53
  require 'mongo/client' # Purposely out-of-order so that database is loaded first
53
54
  require 'mongo/dbref'
54
55
  require 'mongo/grid'
@@ -58,7 +59,9 @@ require 'mongo/server_selector'
58
59
  require 'mongo/session'
59
60
  require 'mongo/socket'
60
61
  require 'mongo/srv'
62
+ require 'mongo/timeout'
61
63
  require 'mongo/uri'
62
64
  require 'mongo/version'
63
65
  require 'mongo/write_concern'
64
66
  require 'mongo/lint'
67
+ require 'mongo/client_encryption'
@@ -180,31 +180,44 @@ module Mongo
180
180
  # @return [ Mongo::Socket::SSL | Mongo::Socket::TCP | Mongo::Socket::Unix ]
181
181
  # The socket.
182
182
  #
183
- # @raise [ Exception ] If network connection failed.
183
+ # @raise [ Mongo::Error ] If network connection failed.
184
184
  #
185
185
  # @since 2.0.0
186
186
  def 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
187
+ map_exceptions do
188
+ if seed.downcase =~ Unix::MATCH
189
+ specific_address = Unix.new(seed.downcase)
190
+ return specific_address.socket(socket_timeout, ssl_options, options)
191
+ end
192
+
193
+ options = {
194
+ connect_timeout: Server::CONNECT_TIMEOUT,
195
+ }.update(options)
191
196
 
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
197
+ # When the driver connects to "localhost", it only attempts IPv4
198
+ # connections. When the driver connects to other hosts, it will
199
+ # attempt both IPv4 and IPv6 connections.
200
+ family = (host == LOCALHOST) ? ::Socket::AF_INET : ::Socket::AF_UNSPEC
201
+ error = nil
202
+ # Sometimes Socket#getaddrinfo returns the same info more than once
203
+ # (multiple identical items in the returned array). It does not make
204
+ # sense to try to connect to the same address more than once, thus
205
+ # eliminate duplicates here.
206
+ infos = ::Socket.getaddrinfo(host, nil, family, ::Socket::SOCK_STREAM)
207
+ results = infos.map do |info|
208
+ [info[4], info[3]]
209
+ end.uniq
210
+ results.each do |family, address_str|
211
+ begin
212
+ specific_address = FAMILY_MAP[family].new(address_str, port, host)
213
+ socket = specific_address.socket(socket_timeout, ssl_options, options)
214
+ return socket
215
+ rescue IOError, SystemCallError, Error::SocketTimeoutError, Error::SocketError => e
216
+ error = e
217
+ end
205
218
  end
219
+ raise error
206
220
  end
207
- raise error
208
221
  end
209
222
 
210
223
  # Get the address as a string.
@@ -237,5 +250,17 @@ module Mongo
237
250
  else IPv4.parse(address)
238
251
  end
239
252
  end
253
+
254
+ def map_exceptions
255
+ begin
256
+ yield
257
+ rescue Errno::ETIMEDOUT => e
258
+ raise Error::SocketTimeoutError, "#{e.class}: #{e} (for #{self})"
259
+ rescue IOError, SystemCallError => e
260
+ raise Error::SocketError, "#{e.class}: #{e} (for #{self})"
261
+ rescue OpenSSL::SSL::SSLError => e
262
+ raise Error::SocketError, "#{e.class}: #{e} (for #{self}) (#{SSL_ERROR})"
263
+ end
264
+ end
240
265
  end
241
266
  end
@@ -12,6 +12,7 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
+ require 'mongo/auth/credential_cache'
15
16
  require 'mongo/auth/cr'
16
17
  require 'mongo/auth/ldap'
17
18
  require 'mongo/auth/scram'
@@ -0,0 +1,51 @@
1
+ # Copyright (C) 2019 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
+ module Auth
17
+
18
+ # Cache store for computed SCRAM credentials.
19
+ #
20
+ # @api private
21
+ module CredentialCache
22
+
23
+ class << self
24
+ attr_reader :store
25
+ end
26
+
27
+ module_function def get(key)
28
+ @store ||= {}
29
+ @store[key]
30
+ end
31
+
32
+ module_function def set(key, value)
33
+ @store ||= {}
34
+ @store[key] = value
35
+ end
36
+
37
+ module_function def cache(key)
38
+ value = get(key)
39
+ if value.nil?
40
+ value = yield
41
+ set(key, value)
42
+ end
43
+ value
44
+ end
45
+
46
+ module_function def clear
47
+ @store = {}
48
+ end
49
+ end
50
+ end
51
+ end
@@ -36,6 +36,7 @@ module Mongo
36
36
  # The client key string.
37
37
  #
38
38
  # @since 2.0.0
39
+ # @deprecated
39
40
  CLIENT_KEY = 'Client Key'.freeze
40
41
 
41
42
  # The key for the done field in the responses.
@@ -78,6 +79,7 @@ module Mongo
78
79
  # The server key string.
79
80
  #
80
81
  # @since 2.0.0
82
+ # @deprecated
81
83
  SERVER_KEY = 'Server Key'.freeze
82
84
 
83
85
  # The server signature verifier in the response.
@@ -113,12 +115,6 @@ module Mongo
113
115
  def continue(reply, connection)
114
116
  validate_first_message!(reply, connection.server)
115
117
 
116
- # The salted password needs to be calculated now; otherwise, if the
117
- # client key is cached from a previous authentication, the salt in the
118
- # reply will no longer be available for when the salted password is
119
- # needed to calculate the server key.
120
- salted_password
121
-
122
118
  if connection && connection.features.op_msg_enabled?
123
119
  selector = CLIENT_CONTINUE_MESSAGE.merge(
124
120
  payload: client_final_message,
@@ -234,7 +230,6 @@ module Mongo
234
230
 
235
231
  @user = user
236
232
  @nonce = SecureRandom.base64
237
- @client_key = user.send(:client_key)
238
233
  @mechanism = mechanism
239
234
  end
240
235
 
@@ -301,9 +296,9 @@ module Mongo
301
296
  #
302
297
  # @since 2.0.0
303
298
  def client_key
304
- @client_key ||= hmac(salted_password, CLIENT_KEY)
305
- user.instance_variable_set(:@client_key, @client_key) unless user.send(:client_key)
306
- @client_key
299
+ @client_key ||= CredentialCache.cache(cache_key(:client_key)) do
300
+ hmac(salted_password, 'Client Key')
301
+ end
307
302
  end
308
303
 
309
304
  # Client proof algorithm implementation.
@@ -429,6 +424,11 @@ module Mongo
429
424
  @salt ||= payload_data.match(SALT)[1]
430
425
  end
431
426
 
427
+ # @api private
428
+ def cache_key(*extra)
429
+ [user.password, salt, iterations, @mechanism] + extra
430
+ end
431
+
432
432
  # Salted password algorithm implementation.
433
433
  #
434
434
  # @api private
@@ -437,11 +437,13 @@ module Mongo
437
437
  #
438
438
  # @since 2.0.0
439
439
  def salted_password
440
- @salted_password ||= case @mechanism
441
- when :scram256
442
- hi(user.sasl_prepped_password)
443
- else
444
- hi(user.hashed_password)
440
+ @salted_password ||= CredentialCache.cache(cache_key(:salted_password)) do
441
+ case @mechanism
442
+ when :scram256
443
+ hi(user.sasl_prepped_password)
444
+ else
445
+ hi(user.hashed_password)
446
+ end
445
447
  end
446
448
  end
447
449
 
@@ -453,7 +455,9 @@ module Mongo
453
455
  #
454
456
  # @since 2.0.0
455
457
  def server_key
456
- @server_key ||= hmac(salted_password, SERVER_KEY)
458
+ @server_key ||= CredentialCache.cache(cache_key(:server_key)) do
459
+ hmac(salted_password, 'Server Key')
460
+ end
457
461
  end
458
462
 
459
463
  # Server signature algorithm implementation.
@@ -155,8 +155,6 @@ module Mongo
155
155
  # If :password and :pwd are both specified, :password takes precedence.
156
156
  # @option options [ Symbol ] :auth_mech The authorization mechanism.
157
157
  # @option options [ Array<String>, Array<Hash> ] roles The user roles.
158
- # @option options [ String ] :client_key The user's client key cached from a previous
159
- # authentication on the same connection.
160
158
  #
161
159
  # @since 2.0.0
162
160
  def initialize(options)
@@ -186,7 +184,6 @@ module Mongo
186
184
  end
187
185
  @auth_mech_properties = options[:auth_mech_properties] || {}
188
186
  @roles = options[:roles] || []
189
- @client_key = options[:client_key]
190
187
  end
191
188
 
192
189
  # Get the specification for the user, used in creation.
@@ -207,11 +204,6 @@ module Mongo
207
204
 
208
205
  private
209
206
 
210
- # The client key for the user.
211
- #
212
- # @return [ String ] The client key for the user.
213
- attr_reader :client_key
214
-
215
207
  # Generate default auth source based on the URI and options
216
208
  #
217
209
  # @api private
@@ -50,7 +50,7 @@ module Mongo
50
50
  db_name: database.name,
51
51
  session: session,
52
52
  write_concern: options[:write_concern] && WriteConcern.get(options[:write_concern]),
53
- ).execute(next_primary(nil, session))
53
+ ).execute(next_primary(nil, session), client: client)
54
54
  end
55
55
  end
56
56
 
@@ -87,7 +87,7 @@ module Mongo
87
87
  db_name: database.name,
88
88
  session: session,
89
89
  write_concern: options[:write_concern] && WriteConcern.get(options[:write_concern]),
90
- ).execute(next_primary(nil, session))
90
+ ).execute(next_primary(nil, session), client: client)
91
91
  end
92
92
  end
93
93
 
@@ -113,7 +113,7 @@ module Mongo
113
113
  db_name: database.name,
114
114
  session: session,
115
115
  write_concern: options[:write_concern] && WriteConcern.get(options[:write_concern]),
116
- ).execute(next_primary(nil, session))
116
+ ).execute(next_primary(nil, session), client: client)
117
117
  end
118
118
  end
119
119
 
@@ -142,7 +142,7 @@ module Mongo
142
142
  user_name: name,
143
143
  db_name: database.name,
144
144
  session: session
145
- ).execute(next_primary(nil, session))
145
+ ).execute(next_primary(nil, session), client: client)
146
146
  end
147
147
  end
148
148
 
@@ -122,7 +122,7 @@ module Mongo
122
122
  @thread.join
123
123
  end
124
124
  break
125
- rescue Timeout::Error
125
+ rescue ::Timeout::Error
126
126
  end
127
127
  end
128
128
 
@@ -203,28 +203,28 @@ module Mongo
203
203
 
204
204
  def delete_one(documents, server, operation_id, session, txn_num)
205
205
  spec = base_spec(operation_id, session).merge(:deletes => documents, :txn_num => txn_num)
206
- Operation::Delete.new(spec).bulk_execute(server)
206
+ Operation::Delete.new(spec).bulk_execute(server, client: client)
207
207
  end
208
208
 
209
209
  def delete_many(documents, server, operation_id, session, txn_num)
210
210
  spec = base_spec(operation_id, session).merge(:deletes => documents)
211
- Operation::Delete.new(spec).bulk_execute(server)
211
+ Operation::Delete.new(spec).bulk_execute(server, client: client)
212
212
  end
213
213
 
214
214
  def insert_one(documents, server, operation_id, session, txn_num)
215
215
  spec = base_spec(operation_id, session).merge(:documents => documents, :txn_num => txn_num)
216
- Operation::Insert.new(spec).bulk_execute(server)
216
+ Operation::Insert.new(spec).bulk_execute(server, client: client)
217
217
  end
218
218
 
219
219
  def update_one(documents, server, operation_id, session, txn_num)
220
220
  spec = base_spec(operation_id, session).merge(:updates => documents, :txn_num => txn_num)
221
- Operation::Update.new(spec).bulk_execute(server)
221
+ Operation::Update.new(spec).bulk_execute(server, client: client)
222
222
  end
223
223
  alias :replace_one :update_one
224
224
 
225
225
  def update_many(documents, server, operation_id, session, txn_num)
226
226
  spec = base_spec(operation_id, session).merge(:updates => documents)
227
- Operation::Update.new(spec).bulk_execute(server)
227
+ Operation::Update.new(spec).bulk_execute(server, client: client)
228
228
  end
229
229
  end
230
230
  end
@@ -27,6 +27,7 @@ module Mongo
27
27
  #
28
28
  # @since 2.1.0
29
29
  CRUD_OPTIONS = [
30
+ :auto_encryption_options,
30
31
  :database,
31
32
  :read, :read_concern,
32
33
  :write, :write_concern,
@@ -53,6 +54,7 @@ module Mongo
53
54
  :auth_mech,
54
55
  :auth_mech_properties,
55
56
  :auth_source,
57
+ :auto_encryption_options,
56
58
  :cleanup,
57
59
  :compressors,
58
60
  :connect,
@@ -119,6 +121,10 @@ module Mongo
119
121
  # @return [ Hash ] options The configuration options.
120
122
  attr_reader :options
121
123
 
124
+ # @return [ Mongo::Crypt::AutoEncrypter ] The object that encapsulates
125
+ # auto-encryption behavior
126
+ attr_reader :encrypter
127
+
122
128
  # Delegate command and collections execution to the current database.
123
129
  def_delegators :@database, :command, :collections
124
130
 
@@ -369,6 +375,44 @@ module Mongo
369
375
  # See Ruby's Zlib module for valid levels.
370
376
  # @option options [ Hash ] :resolv_options For internal driver use only.
371
377
  # Options to pass through to Resolv::DNS constructor for SRV lookups.
378
+ # @option options [ Hash ] :auto_encryption_options Auto-encryption related
379
+ # options.
380
+ # - :key_vault_client => Client | nil, a client connected to the MongoDB
381
+ # instance containing the encryption key vault
382
+ # - :key_vault_namespace => String, the namespace of the key vault in the
383
+ # format database.collection
384
+ # - :kms_providers => Hash, A hash of key management service configuration
385
+ # information. Valid hash keys are :local or :aws. There may be more
386
+ # than one kms provider specified.
387
+ # - :schema_map => Hash | nil, JSONSchema for one or more collections
388
+ # specifying which fields should be encrypted.
389
+ # - Note: Schemas supplied in the schema_map only apply to configuring
390
+ # automatic encryption for client side encryption. Other validation
391
+ # rules in the JSON schema will not be enforced by the driver and will
392
+ # result in an error.
393
+ # - Note: Supplying a schema_map provides more security than relying on
394
+ # JSON Schemas obtained from the server. It protects against a
395
+ # malicious server advertising a false JSON Schema, which could trick
396
+ # the client into sending unencrypted data that should be encrypted.
397
+ # - :bypass_auto_encryption => Boolean, when true, disables auto encryption;
398
+ # defaults to false.
399
+ # - :extra_options => Hash | nil, options related to spawning mongocryptd
400
+ # (this part of the API is subject to change).
401
+ #
402
+ # Notes on automatic encryption:
403
+ # - Automatic encryption is an enterprise only feature that only applies
404
+ # to operations on a collection.
405
+ # - Automatic encryption is not supported for operations on a database or
406
+ # view.
407
+ # - Automatic encryption requires the authenticated user to have the
408
+ # listCollections privilege.
409
+ # - At worst, automatic encryption may triple the number of connections
410
+ # used by the Client at any one time.
411
+ # - If automatic encryption fails on an operation, use a MongoClient
412
+ # configured with bypass_auto_encryption: true and use
413
+ # ClientEncryption.encrypt to manually encrypt values.
414
+ # - Enabling Client Side Encryption reduces the maximum write batch size
415
+ # and may have a negative performance impact.
372
416
  #
373
417
  # @since 2.0.0
374
418
  def initialize(addresses_or_uri, options = nil)
@@ -425,12 +469,32 @@ module Mongo
425
469
  sdam_proc.call(self)
426
470
  end
427
471
 
428
- @cluster = Cluster.new(addresses, @monitoring, cluster_options.merge(srv_uri: srv_uri))
472
+ @connect_lock = Mutex.new
473
+ @connect_lock.synchronize do
474
+ @cluster = Cluster.new(addresses, @monitoring,
475
+ cluster_options.merge(srv_uri: srv_uri))
476
+ end
477
+
478
+ begin
479
+ # Unset monitoring, it will be taken out of cluster from now on
480
+ remove_instance_variable('@monitoring')
429
481
 
430
- # Unset monitoring, it will be taken out of cluster from now on
431
- remove_instance_variable('@monitoring')
482
+ if @options[:auto_encryption_options]
483
+ @connect_lock.synchronize do
484
+ build_encrypter
485
+ end
486
+ end
432
487
 
433
- yield(self) if block_given?
488
+ yield(self) if block_given?
489
+ rescue
490
+ begin
491
+ @cluster.disconnect!
492
+ rescue => e
493
+ log_warn("Eror disconnecting cluster in client constructor's exception handler: #{e.class}: #{e}")
494
+ # Drop this exception so that the original exception is raised
495
+ end
496
+ raise
497
+ end
434
498
  end
435
499
 
436
500
  # @api private
@@ -616,6 +680,8 @@ module Mongo
616
680
  #
617
681
  # @api private
618
682
  def update_options(new_options)
683
+ old_options = @options
684
+
619
685
  validate_new_options!(new_options).tap do |opts|
620
686
  # Our options are frozen
621
687
  options = @options.dup
@@ -625,8 +691,29 @@ module Mongo
625
691
  if options[:write_concern] && opts[:write]
626
692
  options.delete(:write_concern)
627
693
  end
694
+
628
695
  options.update(opts)
629
696
  @options = options.freeze
697
+
698
+ auto_encryption_options_changed =
699
+ @options[:auto_encryption_options] != old_options[:auto_encryption_options]
700
+
701
+ # If there are new auto_encryption_options, create a new encrypter.
702
+ # Otherwise, allow the new client to share an encrypter with the
703
+ # original client.
704
+ #
705
+ # If auto_encryption_options are nil, set @encrypter to nil, but do not
706
+ # close the encrypter because it may still be used by the original client.
707
+ if @options[:auto_encryption_options] && auto_encryption_options_changed
708
+ @connect_lock.synchronize do
709
+ build_encrypter
710
+ end
711
+ elsif @options[:auto_encryption_options].nil?
712
+ @connect_lock.synchronize do
713
+ @encrypter = nil
714
+ end
715
+ end
716
+
630
717
  validate_options!
631
718
  validate_authentication_options!
632
719
  end
@@ -664,7 +751,18 @@ module Mongo
664
751
  #
665
752
  # @since 2.1.0
666
753
  def close
667
- @cluster.disconnect!
754
+ @connect_lock.synchronize do
755
+ do_close
756
+ end
757
+ true
758
+ end
759
+
760
+ # Close encrypter and clean up auto-encryption resources.
761
+ #
762
+ # @return [ true ] Always true.
763
+ def close_encrypter
764
+ @encrypter.close if @encrypter
765
+
668
766
  true
669
767
  end
670
768
 
@@ -679,9 +777,16 @@ module Mongo
679
777
  def reconnect
680
778
  addresses = cluster.addresses.map(&:to_s)
681
779
 
682
- @cluster.disconnect! rescue nil
780
+ @connect_lock.synchronize do
781
+ do_close rescue nil
782
+
783
+ @cluster = Cluster.new(addresses, monitoring, cluster_options)
784
+
785
+ if @options[:auto_encryption_options]
786
+ build_encrypter
787
+ end
788
+ end
683
789
 
684
- @cluster = Cluster.new(addresses, monitoring, cluster_options)
685
790
  true
686
791
  end
687
792
 
@@ -805,6 +910,13 @@ module Mongo
805
910
 
806
911
  private
807
912
 
913
+ # Create a new encrypter object using the client's auto encryption options
914
+ def build_encrypter
915
+ @encrypter = Crypt::AutoEncrypter.new(
916
+ @options[:auto_encryption_options].merge(client: self)
917
+ )
918
+ end
919
+
808
920
  # Generate default client options based on the URI and options
809
921
  # passed into the Client constructor.
810
922
  def default_options(options)
@@ -822,6 +934,12 @@ module Mongo
822
934
  end
823
935
  end
824
936
 
937
+ # Implementation for #close, assumes the connect lock is already acquired.
938
+ def do_close
939
+ @cluster.disconnect!
940
+ close_encrypter
941
+ end
942
+
825
943
  # If options[:session] is set, validates that session and returns it.
826
944
  # If deployment supports sessions, creates a new session and returns it.
827
945
  # The session is implicit unless options[:implicit] is given.
@@ -911,7 +1029,11 @@ module Mongo
911
1029
 
912
1030
  if auth_mech.nil?
913
1031
  if user && user.empty?
914
- raise Mongo::Auth::InvalidConfiguration.new('empty username is not supported for default auth mechanism')
1032
+ raise Mongo::Auth::InvalidConfiguration, 'Empty username is not supported for default auth mechanism'
1033
+ end
1034
+
1035
+ if auth_source == ''
1036
+ raise Mongo::Auth::InvalidConfiguration, 'Auth source cannot be empty for default auth mechanism'
915
1037
  end
916
1038
 
917
1039
  return
@@ -922,23 +1044,30 @@ module Mongo
922
1044
  end
923
1045
 
924
1046
  if user.nil? && auth_mech != :mongodb_x509
925
- raise Mongo::Auth::InvalidConfiguration.new("user is required for mechanism #{auth_mech}")
1047
+ raise Mongo::Auth::InvalidConfiguration, "Username is required for auth mechanism #{auth_mech}"
926
1048
  end
927
1049
 
928
1050
  if password.nil? && ![:gssapi, :mongodb_x509].include?(auth_mech)
929
- raise Mongo::Auth::InvalidConfiguration.new("password is required for mechanism #{auth_mech}")
1051
+ raise Mongo::Auth::InvalidConfiguration, "Password is required for auth mechanism #{auth_mech}"
930
1052
  end
931
1053
 
932
1054
  if password && auth_mech == :mongodb_x509
933
- raise Mongo::Auth::InvalidConfiguration.new('password is not supported for mongodb_x509')
1055
+ raise Mongo::Auth::InvalidConfiguration, 'Password is not supported for :mongodb_x509 auth mechanism'
934
1056
  end
935
1057
 
936
- if !['$external', nil].include?(auth_source) && [:gssapi, :mongodb_x509].include?(auth_mech)
937
- raise Mongo::Auth::InvalidConfiguration.new("#{auth_source} is an invalid auth source for #{auth_mech}; valid options are $external and nil")
1058
+ if [:gssapi, :mongodb_x509].include?(auth_mech)
1059
+ if !['$external', nil].include?(auth_source)
1060
+ raise Mongo::Auth::InvalidConfiguration, "#{auth_source} is an invalid auth source for #{auth_mech}; valid options are $external and nil"
1061
+ end
1062
+ else
1063
+ # Auth source is the database name, and thus cannot be the empty string.
1064
+ if auth_source == ''
1065
+ raise Mongo::Auth::InvalidConfiguration, "Auth source cannot be empty for auth mechanism #{auth_mech}"
1066
+ end
938
1067
  end
939
1068
 
940
1069
  if mech_properties && auth_mech != :gssapi
941
- raise Mongo::Auth::InvalidConfiguration.new("mechanism_properties are not supported for #{auth_mech}")
1070
+ raise Mongo::Auth::InvalidConfiguration, ":mechanism_properties are not supported for auth mechanism #{auth_mech}"
942
1071
  end
943
1072
  end
944
1073