mongo 2.11.4 → 2.12.3

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 (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