mongo 2.11.6 → 2.12.0.rc0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +2 -2
- data.tar.gz.sig +0 -0
- data/CONTRIBUTING.md +1 -1
- data/lib/mongo.rb +3 -0
- data/lib/mongo/address.rb +13 -2
- data/lib/mongo/auth.rb +1 -0
- data/lib/mongo/auth/credential_cache.rb +51 -0
- data/lib/mongo/auth/scram/conversation.rb +20 -16
- data/lib/mongo/auth/user.rb +0 -8
- data/lib/mongo/auth/user/view.rb +4 -4
- data/lib/mongo/background_thread.rb +1 -1
- data/lib/mongo/bulk_write.rb +5 -5
- data/lib/mongo/client.rb +126 -11
- data/lib/mongo/client_encryption.rb +103 -0
- data/lib/mongo/cluster.rb +2 -2
- data/lib/mongo/cluster/reapers/cursor_reaper.rb +18 -6
- data/lib/mongo/cluster/sdam_flow.rb +54 -58
- data/lib/mongo/cluster/srv_monitor.rb +1 -1
- data/lib/mongo/collection.rb +3 -3
- data/lib/mongo/collection/view.rb +1 -1
- data/lib/mongo/collection/view/aggregation.rb +1 -1
- data/lib/mongo/collection/view/change_stream.rb +12 -3
- data/lib/mongo/collection/view/iterable.rb +14 -5
- data/lib/mongo/collection/view/map_reduce.rb +2 -2
- data/lib/mongo/collection/view/readable.rb +7 -9
- data/lib/mongo/collection/view/writable.rb +7 -7
- data/lib/mongo/crypt.rb +33 -0
- data/lib/mongo/crypt/auto_decryption_context.rb +42 -0
- data/lib/mongo/crypt/auto_encrypter.rb +169 -0
- data/lib/mongo/crypt/auto_encryption_context.rb +44 -0
- data/lib/mongo/crypt/binary.rb +155 -0
- data/lib/mongo/crypt/binding.rb +1162 -0
- data/lib/mongo/crypt/context.rb +135 -0
- data/lib/mongo/crypt/data_key_context.rb +162 -0
- data/lib/mongo/crypt/encryption_io.rb +283 -0
- data/lib/mongo/crypt/explicit_decryption_context.rb +40 -0
- data/lib/mongo/crypt/explicit_encrypter.rb +117 -0
- data/lib/mongo/crypt/explicit_encryption_context.rb +89 -0
- data/lib/mongo/crypt/handle.rb +293 -0
- data/lib/mongo/crypt/hooks.rb +90 -0
- data/lib/mongo/crypt/kms_context.rb +67 -0
- data/lib/mongo/crypt/status.rb +131 -0
- data/lib/mongo/cursor.rb +64 -32
- data/lib/mongo/database.rb +13 -6
- data/lib/mongo/database/view.rb +13 -4
- data/lib/mongo/dbref.rb +9 -2
- data/lib/mongo/error.rb +5 -1
- data/lib/mongo/error/crypt_error.rb +31 -0
- data/lib/mongo/error/{failed_stringprep_validation.rb → failed_string_prep_validation.rb} +0 -0
- data/lib/mongo/error/invalid_cursor_operation.rb +27 -0
- data/lib/mongo/error/kms_error.rb +22 -0
- data/lib/mongo/error/max_bson_size.rb +14 -3
- data/lib/mongo/error/mongocryptd_spawn_error.rb +22 -0
- data/lib/mongo/error/no_server_available.rb +8 -3
- data/lib/mongo/error/operation_failure.rb +1 -0
- data/lib/mongo/grid/file.rb +0 -5
- data/lib/mongo/grid/file/chunk.rb +0 -2
- data/lib/mongo/grid/file/info.rb +2 -1
- data/lib/mongo/grid/fs_bucket.rb +13 -15
- data/lib/mongo/grid/stream/write.rb +3 -9
- data/lib/mongo/index/view.rb +3 -3
- data/lib/mongo/monitoring/event/command_started.rb +6 -1
- data/lib/mongo/operation/collections_info.rb +6 -3
- data/lib/mongo/operation/delete/op_msg.rb +1 -1
- data/lib/mongo/operation/find/op_msg.rb +4 -1
- data/lib/mongo/operation/get_more/op_msg.rb +4 -1
- data/lib/mongo/operation/insert/command.rb +2 -2
- data/lib/mongo/operation/insert/legacy.rb +2 -2
- data/lib/mongo/operation/insert/op_msg.rb +3 -3
- data/lib/mongo/operation/result.rb +36 -27
- data/lib/mongo/operation/shared/executable.rb +10 -8
- data/lib/mongo/operation/shared/executable_no_validate.rb +2 -2
- data/lib/mongo/operation/shared/op_msg_or_command.rb +2 -2
- data/lib/mongo/operation/shared/op_msg_or_find_command.rb +2 -2
- data/lib/mongo/operation/shared/op_msg_or_list_indexes_command.rb +2 -2
- data/lib/mongo/operation/shared/write.rb +17 -10
- data/lib/mongo/operation/update/op_msg.rb +1 -1
- data/lib/mongo/protocol/compressed.rb +6 -5
- data/lib/mongo/protocol/insert.rb +3 -1
- data/lib/mongo/protocol/message.rb +72 -8
- data/lib/mongo/protocol/msg.rb +191 -37
- data/lib/mongo/protocol/query.rb +7 -9
- data/lib/mongo/protocol/serializers.rb +6 -2
- data/lib/mongo/server.rb +10 -4
- data/lib/mongo/server/connection.rb +20 -9
- data/lib/mongo/server/connection_base.rb +81 -12
- data/lib/mongo/server/connection_common.rb +61 -0
- data/lib/mongo/server/connection_pool.rb +37 -1
- data/lib/mongo/server/description.rb +9 -11
- data/lib/mongo/server/monitor.rb +2 -0
- data/lib/mongo/server/monitor/connection.rb +3 -18
- data/lib/mongo/server/pending_connection.rb +2 -1
- data/lib/mongo/session.rb +2 -2
- data/lib/mongo/session/session_pool.rb +8 -3
- data/lib/mongo/socket.rb +29 -16
- data/lib/mongo/socket/ssl.rb +23 -8
- data/lib/mongo/socket/tcp.rb +12 -3
- data/lib/mongo/timeout.rb +49 -0
- data/lib/mongo/uri.rb +30 -1
- data/lib/mongo/version.rb +1 -1
- data/mongo.gemspec +1 -1
- data/spec/README.md +134 -7
- data/spec/integration/auth_spec.rb +53 -0
- data/spec/integration/{client_options_spec.rb → client_authentication_options_spec.rb} +10 -10
- data/spec/integration/client_construction_spec.rb +76 -1
- data/spec/integration/client_side_encryption/auto_encryption_bulk_writes_spec.rb +351 -0
- data/spec/integration/client_side_encryption/auto_encryption_command_monitoring_spec.rb +301 -0
- data/spec/integration/client_side_encryption/auto_encryption_mongocryptd_spawn_spec.rb +71 -0
- data/spec/integration/client_side_encryption/auto_encryption_old_wire_version_spec.rb +76 -0
- data/spec/integration/client_side_encryption/auto_encryption_reconnect_spec.rb +216 -0
- data/spec/integration/client_side_encryption/auto_encryption_spec.rb +600 -0
- data/spec/integration/client_side_encryption/bson_size_limit_spec.rb +183 -0
- data/spec/integration/client_side_encryption/bypass_mongocryptd_spawn_spec.rb +74 -0
- data/spec/integration/client_side_encryption/client_close_spec.rb +59 -0
- data/spec/integration/client_side_encryption/corpus_spec.rb +228 -0
- data/spec/integration/client_side_encryption/custom_endpoint_spec.rb +132 -0
- data/spec/integration/client_side_encryption/data_key_spec.rb +163 -0
- data/spec/integration/client_side_encryption/explicit_encryption_spec.rb +114 -0
- data/spec/integration/client_side_encryption/external_key_vault_spec.rb +137 -0
- data/spec/integration/client_side_encryption/views_spec.rb +42 -0
- data/spec/integration/client_update_spec.rb +120 -0
- data/spec/integration/command_monitoring_spec.rb +3 -1
- data/spec/integration/command_spec.rb +44 -10
- data/spec/integration/connection_spec.rb +57 -0
- data/spec/integration/reconnect_spec.rb +7 -6
- data/spec/integration/size_limit_spec.rb +94 -0
- data/spec/integration/srv_monitoring_spec.rb +14 -6
- data/spec/lite_spec_helper.rb +31 -22
- data/spec/mongo/auth/cr_spec.rb +8 -0
- data/spec/mongo/auth/ldap_spec.rb +5 -1
- data/spec/mongo/auth/scram/conversation_spec.rb +5 -6
- data/spec/mongo/auth/scram/negotiation_spec.rb +74 -75
- data/spec/mongo/auth/scram_spec.rb +45 -35
- data/spec/mongo/auth/x509_spec.rb +5 -1
- data/spec/mongo/client_construction_spec.rb +206 -3
- data/spec/mongo/client_encryption_spec.rb +408 -0
- data/spec/mongo/cluster/cursor_reaper_spec.rb +12 -8
- data/spec/mongo/cluster/socket_reaper_spec.rb +14 -3
- data/spec/mongo/collection/view/aggregation_spec.rb +0 -2
- data/spec/mongo/collection/view/change_stream_spec.rb +7 -7
- data/spec/mongo/collection/view/map_reduce_spec.rb +3 -3
- data/spec/mongo/collection/view_spec.rb +1 -1
- data/spec/mongo/collection_spec.rb +4 -33
- data/spec/mongo/crypt/auto_decryption_context_spec.rb +90 -0
- data/spec/mongo/crypt/auto_encrypter_spec.rb +182 -0
- data/spec/mongo/crypt/auto_encryption_context_spec.rb +107 -0
- data/spec/mongo/crypt/binary_spec.rb +115 -0
- data/spec/mongo/crypt/binding/binary_spec.rb +56 -0
- data/spec/mongo/crypt/binding/context_spec.rb +257 -0
- data/spec/mongo/crypt/binding/helpers_spec.rb +46 -0
- data/spec/mongo/crypt/binding/mongocrypt_spec.rb +144 -0
- data/spec/mongo/crypt/binding/status_spec.rb +99 -0
- data/spec/mongo/crypt/binding/version_spec.rb +22 -0
- data/spec/mongo/crypt/binding_unloaded_spec.rb +20 -0
- data/spec/mongo/crypt/data_key_context_spec.rb +213 -0
- data/spec/mongo/crypt/encryption_io_spec.rb +136 -0
- data/spec/mongo/crypt/explicit_decryption_context_spec.rb +72 -0
- data/spec/mongo/crypt/explicit_encryption_context_spec.rb +170 -0
- data/spec/mongo/crypt/handle_spec.rb +198 -0
- data/spec/mongo/crypt/helpers/mongo_crypt_spec_helper.rb +108 -0
- data/spec/mongo/crypt/status_spec.rb +152 -0
- data/spec/mongo/cursor_spec.rb +24 -4
- data/spec/mongo/database_spec.rb +20 -0
- data/spec/mongo/error/crypt_error_spec.rb +26 -0
- data/spec/mongo/error/max_bson_size_spec.rb +35 -0
- data/spec/mongo/error/no_server_available_spec.rb +11 -1
- data/spec/mongo/error/operation_failure_spec.rb +6 -6
- data/spec/mongo/operation/aggregate_spec.rb +1 -1
- data/spec/mongo/operation/collections_info_spec.rb +1 -1
- data/spec/mongo/operation/command_spec.rb +3 -3
- data/spec/mongo/operation/create_index_spec.rb +3 -3
- data/spec/mongo/operation/create_user_spec.rb +3 -3
- data/spec/mongo/operation/delete/bulk_spec.rb +6 -6
- data/spec/mongo/operation/delete/op_msg_spec.rb +1 -6
- data/spec/mongo/operation/delete_spec.rb +7 -7
- data/spec/mongo/operation/drop_index_spec.rb +2 -2
- data/spec/mongo/operation/find/legacy_spec.rb +1 -1
- data/spec/mongo/operation/get_more_spec.rb +1 -1
- data/spec/mongo/operation/indexes_spec.rb +1 -1
- data/spec/mongo/operation/insert/bulk_spec.rb +7 -7
- data/spec/mongo/operation/insert/op_msg_spec.rb +3 -6
- data/spec/mongo/operation/insert_spec.rb +12 -12
- data/spec/mongo/operation/map_reduce_spec.rb +2 -2
- data/spec/mongo/operation/remove_user_spec.rb +3 -3
- data/spec/mongo/operation/update/bulk_spec.rb +6 -6
- data/spec/mongo/operation/update/op_msg_spec.rb +3 -6
- data/spec/mongo/operation/update_spec.rb +7 -7
- data/spec/mongo/operation/update_user_spec.rb +1 -1
- data/spec/mongo/protocol/compressed_spec.rb +2 -3
- data/spec/mongo/protocol/delete_spec.rb +9 -8
- data/spec/mongo/protocol/get_more_spec.rb +9 -8
- data/spec/mongo/protocol/insert_spec.rb +9 -8
- data/spec/mongo/protocol/kill_cursors_spec.rb +6 -5
- data/spec/mongo/protocol/msg_spec.rb +57 -53
- data/spec/mongo/protocol/query_spec.rb +12 -12
- data/spec/mongo/protocol/registry_spec.rb +1 -1
- data/spec/mongo/protocol/reply_spec.rb +1 -1
- data/spec/mongo/protocol/update_spec.rb +10 -9
- data/spec/mongo/server/connection_pool_spec.rb +1 -1
- data/spec/mongo/server/connection_spec.rb +28 -7
- data/spec/mongo/socket_spec.rb +1 -1
- data/spec/mongo/timeout_spec.rb +85 -0
- data/spec/mongo/uri/srv_protocol_spec.rb +2 -2
- data/spec/mongo/uri_spec.rb +52 -5
- data/spec/mongo/write_concern_spec.rb +13 -1
- data/spec/{support → runners}/auth.rb +14 -1
- data/spec/{support → runners}/change_streams.rb +1 -1
- data/spec/{support → runners}/change_streams/operation.rb +0 -0
- data/spec/{support → runners}/cmap.rb +1 -1
- data/spec/{support → runners}/cmap/verifier.rb +0 -0
- data/spec/{support → runners}/command_monitoring.rb +0 -0
- data/spec/runners/connection_string.rb +358 -4
- data/spec/{support → runners}/crud.rb +9 -9
- data/spec/{support → runners}/crud/context.rb +0 -0
- data/spec/{support → runners}/crud/operation.rb +7 -3
- data/spec/{support → runners}/crud/outcome.rb +0 -0
- data/spec/{support → runners}/crud/requirement.rb +1 -1
- data/spec/{support → runners}/crud/spec.rb +12 -1
- data/spec/{support → runners}/crud/test.rb +0 -0
- data/spec/{support → runners}/crud/test_base.rb +0 -0
- data/spec/{support → runners}/crud/verifier.rb +10 -12
- data/spec/{support → runners}/gridfs.rb +0 -0
- data/spec/{support → runners}/sdam_monitoring.rb +0 -0
- data/spec/{support → runners}/server_discovery_and_monitoring.rb +0 -0
- data/spec/{support → runners}/server_selection.rb +0 -0
- data/spec/{support → runners}/server_selection_rtt.rb +0 -0
- data/spec/{support → runners}/transactions.rb +4 -4
- data/spec/{support → runners}/transactions/context.rb +0 -0
- data/spec/{support → runners}/transactions/operation.rb +0 -0
- data/spec/{support → runners}/transactions/spec.rb +0 -0
- data/spec/{support → runners}/transactions/test.rb +37 -5
- data/spec/spec_helper.rb +0 -5
- data/spec/spec_tests/auth_spec.rb +3 -3
- data/spec/spec_tests/client_side_encryption_spec.rb +13 -0
- data/spec/spec_tests/connection_string_spec.rb +1 -1
- data/spec/spec_tests/data/auth/connection-string.yml +13 -0
- data/spec/spec_tests/data/client_side_encryption/aggregate.yml +134 -0
- data/spec/spec_tests/data/client_side_encryption/badQueries.yml +526 -0
- data/spec/spec_tests/data/client_side_encryption/badSchema.yml +73 -0
- data/spec/spec_tests/data/client_side_encryption/basic.yml +116 -0
- data/spec/spec_tests/data/client_side_encryption/bulk.yml +85 -0
- data/spec/spec_tests/data/client_side_encryption/bypassAutoEncryption.yml +100 -0
- data/spec/spec_tests/data/client_side_encryption/bypassedCommand.yml +42 -0
- data/spec/spec_tests/data/client_side_encryption/count.yml +61 -0
- data/spec/spec_tests/data/client_side_encryption/countDocuments.yml +59 -0
- data/spec/spec_tests/data/client_side_encryption/delete.yml +105 -0
- data/spec/spec_tests/data/client_side_encryption/distinct.yml +73 -0
- data/spec/spec_tests/data/client_side_encryption/explain.yml +64 -0
- data/spec/spec_tests/data/client_side_encryption/find.yml +119 -0
- data/spec/spec_tests/data/client_side_encryption/findOneAndDelete.yml +57 -0
- data/spec/spec_tests/data/client_side_encryption/findOneAndReplace.yml +57 -0
- data/spec/spec_tests/data/client_side_encryption/findOneAndUpdate.yml +57 -0
- data/spec/spec_tests/data/client_side_encryption/getMore.yml +68 -0
- data/spec/spec_tests/data/client_side_encryption/insert.yml +102 -0
- data/spec/spec_tests/data/client_side_encryption/keyAltName.yml +71 -0
- data/spec/spec_tests/data/client_side_encryption/localKMS.yml +54 -0
- data/spec/spec_tests/data/client_side_encryption/localSchema.yml +72 -0
- data/spec/spec_tests/data/client_side_encryption/malformedCiphertext.yml +69 -0
- data/spec/spec_tests/data/client_side_encryption/maxWireVersion.yml +20 -0
- data/spec/spec_tests/data/client_side_encryption/missingKey.yml +49 -0
- data/spec/spec_tests/data/client_side_encryption/replaceOne.yml +61 -0
- data/spec/spec_tests/data/client_side_encryption/types.yml +527 -0
- data/spec/spec_tests/data/client_side_encryption/unsupportedCommand.yml +25 -0
- data/spec/spec_tests/data/client_side_encryption/updateMany.yml +77 -0
- data/spec/spec_tests/data/client_side_encryption/updateOne.yml +168 -0
- data/spec/spec_tests/data/read_write_concern/connection-string/write-concern.yml +1 -4
- data/spec/spec_tests/data/retryable_writes/insertOne-serverErrors.yml +21 -0
- data/spec/spec_tests/data/sdam/rs/incompatible_ghost.yml +2 -4
- data/spec/spec_tests/data/sdam/rs/incompatible_other.yml +1 -1
- data/spec/spec_tests/data/sdam/rs/primary_mismatched_me_not_removed.yml +73 -0
- data/spec/spec_tests/data/sdam/rs/primary_to_no_primary_mismatched_me.yml +1 -2
- data/spec/spec_tests/data/sdam/rs/repeated.yml +101 -0
- data/spec/spec_tests/data/sdam/rs/{primary_address_change.yml → ruby_primary_address_change.yml} +2 -0
- 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
- data/spec/spec_tests/data/sdam/sharded/ruby_discovered_single_mongos.yml +27 -0
- data/spec/spec_tests/data/sdam/sharded/{primary_address_change.yml → ruby_primary_different_address.yml} +1 -1
- data/spec/spec_tests/data/sdam/sharded/{primary_mismatched_me.yml → ruby_primary_mismatched_me.yml} +1 -1
- data/spec/spec_tests/data/sdam/single/{primary_address_change.yml → ruby_primary_different_address.yml} +1 -1
- data/spec/spec_tests/data/sdam/single/{primary_mismatched_me.yml → ruby_primary_mismatched_me.yml} +1 -1
- data/spec/spec_tests/data/sdam_monitoring/{replica_set_with_primary_change.yml → replica_set_primary_address_change.yml} +27 -5
- data/spec/spec_tests/data/sdam_monitoring/replica_set_with_me_mismatch.yml +26 -74
- data/spec/spec_tests/data/sdam_monitoring/replica_set_with_removal.yml +20 -16
- data/spec/spec_tests/data/sdam_monitoring/standalone_suppress_equal_description_changes.yml +73 -0
- data/spec/spec_tests/data/transactions/pin-mongos.yml +2 -3
- data/spec/spec_tests/data/uri_options/auth-options.yml +10 -0
- data/spec/spec_tests/data/uri_options/tls-options.yml +75 -4
- data/spec/spec_tests/read_write_concern_connection_string_spec.rb +1 -1
- data/spec/spec_tests/uri_options_spec.rb +6 -8
- data/spec/stress/connection_pool_timing_spec.rb +6 -3
- data/spec/support/certificates/README.md +4 -0
- data/spec/support/certificates/server-second-level-bundle.pem +77 -77
- data/spec/support/certificates/server-second-level.crt +52 -52
- data/spec/support/certificates/server-second-level.key +25 -25
- data/spec/support/certificates/server-second-level.pem +77 -77
- data/spec/support/client_registry.rb +19 -3
- data/spec/support/cluster_config.rb +9 -1
- data/spec/support/common_shortcuts.rb +12 -0
- data/spec/support/constraints.rb +16 -0
- data/spec/support/crypt.rb +140 -0
- data/spec/support/crypt/corpus/corpus-key-aws.json +33 -0
- data/spec/support/crypt/corpus/corpus-key-local.json +31 -0
- data/spec/support/crypt/corpus/corpus-schema.json +2057 -0
- data/spec/support/crypt/corpus/corpus.json +3657 -0
- data/spec/support/crypt/corpus/corpus_encrypted.json +4152 -0
- data/spec/support/crypt/data_keys/key_document_aws.json +34 -0
- data/spec/support/crypt/data_keys/key_document_local.json +31 -0
- data/spec/support/crypt/external/external-key.json +31 -0
- data/spec/support/crypt/external/external-schema.json +19 -0
- data/spec/support/crypt/limits/limits-doc.json +102 -0
- data/spec/support/crypt/limits/limits-key.json +31 -0
- data/spec/support/crypt/limits/limits-schema.json +1405 -0
- data/spec/support/crypt/schema_maps/schema_map_aws.json +17 -0
- data/spec/support/crypt/schema_maps/schema_map_aws_key_alt_names.json +12 -0
- data/spec/support/crypt/schema_maps/schema_map_local.json +18 -0
- data/spec/support/crypt/schema_maps/schema_map_local_key_alt_names.json +12 -0
- data/spec/support/lite_constraints.rb +17 -1
- data/spec/support/matchers.rb +19 -0
- data/spec/support/shared/protocol.rb +2 -0
- data/spec/support/spec_config.rb +43 -13
- data/spec/support/utils.rb +132 -10
- metadata +277 -81
- metadata.gz.sig +0 -0
- data/spec/integration/grid_fs_bucket_spec.rb +0 -48
- data/spec/integration/zlib_compression_spec.rb +0 -25
- data/spec/spec_tests/data/sdam/sharded/single_mongos.yml +0 -33
- data/spec/support/connection_string.rb +0 -354
@@ -0,0 +1,135 @@
|
|
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 Crypt
|
17
|
+
|
18
|
+
# A wrapper around mongocrypt_ctx_t, which manages the
|
19
|
+
# state machine for encryption and decription.
|
20
|
+
#
|
21
|
+
# This class is a superclass that defines shared methods
|
22
|
+
# amongst contexts that are initialized for different purposes
|
23
|
+
# (e.g. data key creation, encryption, explicit encryption, etc.)
|
24
|
+
#
|
25
|
+
# @api private
|
26
|
+
class Context
|
27
|
+
# Create a new Context object
|
28
|
+
#
|
29
|
+
# @param [ FFI::Pointer ] ctx A pointer to a mongocrypt_t object
|
30
|
+
# used to create a new mongocrypt_ctx_t
|
31
|
+
# @param [ ClientEncryption::IO ] A instance of the IO class
|
32
|
+
# that implements driver I/O methods required to run the
|
33
|
+
# state machine
|
34
|
+
def initialize(mongocrypt_handle, io)
|
35
|
+
# Ideally, this level of the API wouldn't be passing around pointer
|
36
|
+
# references between objects, so this method signature is subject to change.
|
37
|
+
|
38
|
+
# FFI::AutoPointer uses a custom release strategy to automatically free
|
39
|
+
# the pointer once this object goes out of scope
|
40
|
+
@ctx_p = FFI::AutoPointer.new(
|
41
|
+
Binding.mongocrypt_ctx_new(mongocrypt_handle.ref),
|
42
|
+
Binding.method(:mongocrypt_ctx_destroy)
|
43
|
+
)
|
44
|
+
|
45
|
+
@encryption_io = io
|
46
|
+
end
|
47
|
+
|
48
|
+
attr_reader :ctx_p
|
49
|
+
|
50
|
+
# Returns the state of the mongocrypt_ctx_t
|
51
|
+
#
|
52
|
+
# @return [ Symbol ] The context state
|
53
|
+
def state
|
54
|
+
Binding.mongocrypt_ctx_state(@ctx_p)
|
55
|
+
end
|
56
|
+
|
57
|
+
# Runs the mongocrypt_ctx_t state machine and handles
|
58
|
+
# all I/O on behalf of libmongocrypt
|
59
|
+
#
|
60
|
+
# @return [ BSON::Document ] A BSON document representing the outcome
|
61
|
+
# of the state machine. Contents can differ depending on how the
|
62
|
+
# context was initialized..
|
63
|
+
#
|
64
|
+
# @raise [ Error::CryptError ] If the state machine enters the
|
65
|
+
# :error state
|
66
|
+
#
|
67
|
+
# This method is not currently unit tested. It is integration tested
|
68
|
+
# in spec/integration/explicit_encryption_spec.rb
|
69
|
+
def run_state_machine
|
70
|
+
while true
|
71
|
+
case state
|
72
|
+
when :error
|
73
|
+
Binding.check_ctx_status(self)
|
74
|
+
when :ready
|
75
|
+
# Finalize the state machine and return the result as a BSON::Document
|
76
|
+
return Binding.ctx_finalize(self)
|
77
|
+
when :done
|
78
|
+
return nil
|
79
|
+
when :need_mongo_keys
|
80
|
+
filter = Binding.ctx_mongo_op(self)
|
81
|
+
|
82
|
+
@encryption_io.find_keys(filter).each do |key|
|
83
|
+
mongocrypt_feed(key) if key
|
84
|
+
end
|
85
|
+
|
86
|
+
mongocrypt_done
|
87
|
+
when :need_mongo_collinfo
|
88
|
+
filter = Binding.ctx_mongo_op(self)
|
89
|
+
|
90
|
+
result = @encryption_io.collection_info(@db_name, filter)
|
91
|
+
mongocrypt_feed(result) if result
|
92
|
+
|
93
|
+
mongocrypt_done
|
94
|
+
when :need_mongo_markings
|
95
|
+
cmd = Binding.ctx_mongo_op(self)
|
96
|
+
|
97
|
+
result = @encryption_io.mark_command(cmd)
|
98
|
+
mongocrypt_feed(result)
|
99
|
+
|
100
|
+
mongocrypt_done
|
101
|
+
when :need_kms
|
102
|
+
while kms_context = Binding.ctx_next_kms_ctx(self) do
|
103
|
+
@encryption_io.feed_kms(kms_context)
|
104
|
+
end
|
105
|
+
|
106
|
+
Binding.ctx_kms_done(self)
|
107
|
+
else
|
108
|
+
raise Error::CryptError.new(
|
109
|
+
# TODO: fix CryptError to improve this API -- the first argument
|
110
|
+
# in the initializer should not be optional
|
111
|
+
nil,
|
112
|
+
"State #{state} is not supported by Mongo::Crypt::Context"
|
113
|
+
)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
private
|
119
|
+
|
120
|
+
# Indicate that state machine is done feeding I/O responses back to libmongocrypt
|
121
|
+
def mongocrypt_done
|
122
|
+
Binding.mongocrypt_ctx_mongo_done(ctx_p)
|
123
|
+
end
|
124
|
+
|
125
|
+
# Feeds the result of a Mongo operation back to libmongocrypt.
|
126
|
+
#
|
127
|
+
# @param [ Hash ] doc BSON document to feed.
|
128
|
+
#
|
129
|
+
# @return [ BSON::Document ] BSON document containing the result.
|
130
|
+
def mongocrypt_feed(doc)
|
131
|
+
Binding.ctx_mongo_feed(self, doc)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,162 @@
|
|
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 Crypt
|
17
|
+
|
18
|
+
# A Context object initialized specifically for the purpose of creating
|
19
|
+
# a data key in the key managemenet system.
|
20
|
+
#
|
21
|
+
# @api private
|
22
|
+
class DataKeyContext < Context
|
23
|
+
|
24
|
+
# Create a new DataKeyContext object
|
25
|
+
#
|
26
|
+
# @param [ Mongo::Crypt::Handle ] mongocrypt a Handle that
|
27
|
+
# wraps a mongocrypt_t object used to create a new mongocrypt_ctx_t
|
28
|
+
# @param [ Mongo::Crypt::EncryptionIO ] io An object that performs all
|
29
|
+
# driver I/O on behalf of libmongocrypt
|
30
|
+
# @param [ String ] kms_provider The KMS provider to use. Options are
|
31
|
+
# "aws" and "local".
|
32
|
+
# @param [ Hash ] options Data key creation options.
|
33
|
+
#
|
34
|
+
# @option options [ Hash ] :master_key A Hash of options related to the AWS
|
35
|
+
# KMS provider option. Required if kms_provider is "aws".
|
36
|
+
# - :region [ String ] The The AWS region of the master key (required).
|
37
|
+
# - :key [ String ] The Amazon Resource Name (ARN) of the master key (required).
|
38
|
+
# - :endpoint [ String ] An alternate host to send KMS requests to (optional).
|
39
|
+
# @option options [ Array<String> ] :key_alt_names An optional array of strings specifying
|
40
|
+
# alternate names for the new data key.
|
41
|
+
def initialize(mongocrypt, io, kms_provider, options={})
|
42
|
+
super(mongocrypt, io)
|
43
|
+
|
44
|
+
case kms_provider
|
45
|
+
when 'local'
|
46
|
+
Binding.ctx_setopt_master_key_local(self)
|
47
|
+
when 'aws'
|
48
|
+
unless options
|
49
|
+
raise ArgumentError.new(
|
50
|
+
'When "aws" is specified as the KMS provider, options cannot be nil'
|
51
|
+
)
|
52
|
+
end
|
53
|
+
|
54
|
+
unless options.key?(:master_key)
|
55
|
+
raise ArgumentError.new(
|
56
|
+
'When "aws" is specified as the KMS provider, the options Hash ' +
|
57
|
+
'must contain a key named :master_key with a Hash value in the ' +
|
58
|
+
'{ region: "AWS-REGION", key: "AWS-KEY-ARN" }'
|
59
|
+
)
|
60
|
+
end
|
61
|
+
|
62
|
+
master_key_opts = options[:master_key]
|
63
|
+
|
64
|
+
set_aws_master_key(master_key_opts)
|
65
|
+
set_aws_endpoint(master_key_opts[:endpoint]) if master_key_opts[:endpoint]
|
66
|
+
else
|
67
|
+
raise ArgumentError.new(
|
68
|
+
"#{kms_provider} is an invalid kms provider. " +
|
69
|
+
"Valid options are 'aws' and 'local'"
|
70
|
+
)
|
71
|
+
end
|
72
|
+
|
73
|
+
set_key_alt_names(options[:key_alt_names]) if options[:key_alt_names]
|
74
|
+
initialize_ctx
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
# Configure the underlying mongocrypt_ctx_t object to accept AWS
|
80
|
+
# KMS options
|
81
|
+
def set_aws_master_key(master_key_opts)
|
82
|
+
unless master_key_opts
|
83
|
+
raise ArgumentError.new('The :master_key option cannot be nil')
|
84
|
+
end
|
85
|
+
|
86
|
+
unless master_key_opts.is_a?(Hash)
|
87
|
+
raise ArgumentError.new(
|
88
|
+
"#{master_key_opts} is an invalid :master_key option. " +
|
89
|
+
"The :master_key option must be a Hash in the format " +
|
90
|
+
"{ region: 'AWS-REGION', key: 'AWS-KEY-ARN' }"
|
91
|
+
)
|
92
|
+
end
|
93
|
+
|
94
|
+
region = master_key_opts[:region]
|
95
|
+
unless region
|
96
|
+
raise ArgumentError.new(
|
97
|
+
'The value of :region option of the :master_key options hash cannot be nil'
|
98
|
+
)
|
99
|
+
end
|
100
|
+
|
101
|
+
unless region.is_a?(String)
|
102
|
+
raise ArgumentError.new(
|
103
|
+
"#{master_key_opts[:region]} is an invalid AWS master_key region. " +
|
104
|
+
"The value of :region option of the :master_key options hash must be a String"
|
105
|
+
)
|
106
|
+
end
|
107
|
+
|
108
|
+
key = master_key_opts[:key]
|
109
|
+
unless key
|
110
|
+
raise ArgumentError.new(
|
111
|
+
'The value of :key option of the :master_key options hash cannot be nil'
|
112
|
+
)
|
113
|
+
end
|
114
|
+
|
115
|
+
unless key.is_a?(String)
|
116
|
+
raise ArgumentError.new(
|
117
|
+
"#{master_key_opts[:key]} is an invalid AWS master_key key. " +
|
118
|
+
"The value of :key option of the :master_key options hash must be a String"
|
119
|
+
)
|
120
|
+
end
|
121
|
+
|
122
|
+
Binding.ctx_setopt_master_key_aws(
|
123
|
+
self,
|
124
|
+
region,
|
125
|
+
key,
|
126
|
+
)
|
127
|
+
end
|
128
|
+
|
129
|
+
def set_aws_endpoint(endpoint)
|
130
|
+
unless endpoint.is_a?(String)
|
131
|
+
raise ArgumentError.new(
|
132
|
+
"#{endpoint} is an invalid AWS master_key endpoint. " +
|
133
|
+
"The value of :endpoint option of the :master_key options hash must be a String"
|
134
|
+
)
|
135
|
+
end
|
136
|
+
|
137
|
+
Binding.ctx_setopt_master_key_aws_endpoint(self, endpoint)
|
138
|
+
end
|
139
|
+
|
140
|
+
# Set the alt names option on the context
|
141
|
+
def set_key_alt_names(key_alt_names)
|
142
|
+
unless key_alt_names.is_a?(Array)
|
143
|
+
raise ArgumentError.new, 'The :key_alt_names option must be an Array'
|
144
|
+
end
|
145
|
+
|
146
|
+
unless key_alt_names.all? { |key_alt_name| key_alt_name.is_a?(String) }
|
147
|
+
raise ArgumentError.new(
|
148
|
+
"#{key_alt_names} contains an invalid alternate key name. All " +
|
149
|
+
"values of the :key_alt_names option Array must be Strings"
|
150
|
+
)
|
151
|
+
end
|
152
|
+
|
153
|
+
Binding.ctx_setopt_key_alt_names(self, key_alt_names)
|
154
|
+
end
|
155
|
+
|
156
|
+
# Initializes the underlying mongocrypt_ctx_t object
|
157
|
+
def initialize_ctx
|
158
|
+
Binding.ctx_datakey_init(self)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
@@ -0,0 +1,283 @@
|
|
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 Crypt
|
17
|
+
|
18
|
+
# A class that implements I/O methods between the driver and
|
19
|
+
# the MongoDB server or mongocryptd.
|
20
|
+
#
|
21
|
+
# @api private
|
22
|
+
class EncryptionIO
|
23
|
+
|
24
|
+
# Timeout used for SSL socket connection, reading, and writing.
|
25
|
+
# There is no specific timeout written in the spec. See SPEC-1394
|
26
|
+
# for a discussion and updates on what this timeout should be.
|
27
|
+
SOCKET_TIMEOUT = 10
|
28
|
+
|
29
|
+
# Creates a new EncryptionIO object with information about how to connect
|
30
|
+
# to the key vault.
|
31
|
+
#
|
32
|
+
# @param [ Mongo::Client ] client: The client used to connect to the collection
|
33
|
+
# that stores the encrypted documents, defaults to nil.
|
34
|
+
# @param [ Mongo::Client ] mongocryptd_client: The client connected to mongocryptd,
|
35
|
+
# defaults to nil.
|
36
|
+
# @param [ Mongo::Client ] key_vault_client: The client connected to the
|
37
|
+
# key vault collection.
|
38
|
+
# @param [ String ] key_vault_namespace: The key vault namespace in the format
|
39
|
+
# db_name.collection_name.
|
40
|
+
# @param [ Hash ] mongocryptd_options: Options related to mongocryptd.
|
41
|
+
#
|
42
|
+
# @option mongocryptd_options [ Boolean ] :mongocryptd_bypass_spawn
|
43
|
+
# @option mongocryptd_options [ String ] :mongocryptd_spawn_path
|
44
|
+
# @option mongocryptd_options [ Array<String> ] :mongocryptd_spawn_args
|
45
|
+
#
|
46
|
+
# @note When being used for auto encryption, all arguments are required.
|
47
|
+
# When being used for explicit encryption, only the key_vault_namespace
|
48
|
+
# and key_vault_client arguments are required.
|
49
|
+
#
|
50
|
+
# @note This class expects that the key_vault_client and key_vault_namespace
|
51
|
+
# options are not nil and are in the correct format.
|
52
|
+
def initialize(
|
53
|
+
client: nil, mongocryptd_client: nil, key_vault_namespace:,
|
54
|
+
key_vault_client:, mongocryptd_options: {}
|
55
|
+
)
|
56
|
+
validate_key_vault_client!(key_vault_client)
|
57
|
+
validate_key_vault_namespace!(key_vault_namespace)
|
58
|
+
|
59
|
+
@client = client
|
60
|
+
@mongocryptd_client = mongocryptd_client
|
61
|
+
@key_vault_db_name, @key_vault_collection_name = key_vault_namespace.split('.')
|
62
|
+
@key_vault_client = key_vault_client
|
63
|
+
@options = mongocryptd_options
|
64
|
+
end
|
65
|
+
|
66
|
+
# Query for keys in the key vault collection using the provided
|
67
|
+
# filter
|
68
|
+
#
|
69
|
+
# @param [ Hash ] filter
|
70
|
+
#
|
71
|
+
# @return [ Array<BSON::Document> ] The query results
|
72
|
+
def find_keys(filter)
|
73
|
+
key_vault_collection.find(filter).to_a
|
74
|
+
end
|
75
|
+
|
76
|
+
# Insert a document into the key vault collection
|
77
|
+
#
|
78
|
+
# @param [ Hash ] document
|
79
|
+
#
|
80
|
+
# @return [ Mongo::Operation::Insert::Result ] The insertion result
|
81
|
+
def insert_data_key(document)
|
82
|
+
key_vault_collection.insert_one(document)
|
83
|
+
end
|
84
|
+
|
85
|
+
# Get collection info for a collection matching the provided filter
|
86
|
+
#
|
87
|
+
# @param [ Hash ] filter
|
88
|
+
#
|
89
|
+
# @return [ Hash ] The collection information
|
90
|
+
def collection_info(db_name, filter)
|
91
|
+
unless @client
|
92
|
+
raise ArgumentError, 'collection_info requires client to have been passed to the constructor, but it was not'
|
93
|
+
end
|
94
|
+
|
95
|
+
@client.use(db_name).database.list_collections(filter: filter).first
|
96
|
+
end
|
97
|
+
|
98
|
+
# Send the command to mongocryptd to be marked with intent-to-encrypt markings
|
99
|
+
#
|
100
|
+
# @param [ Hash ] cmd
|
101
|
+
#
|
102
|
+
# @return [ Hash ] The marked command
|
103
|
+
def mark_command(cmd)
|
104
|
+
unless @mongocryptd_client
|
105
|
+
raise ArgumentError, 'mark_command requires mongocryptd_client to have been passed to the constructor, but it was not'
|
106
|
+
end
|
107
|
+
|
108
|
+
begin
|
109
|
+
response = @mongocryptd_client.database.command(cmd)
|
110
|
+
rescue Error::NoServerAvailable => e
|
111
|
+
raise e if @options[:mongocryptd_bypass_spawn]
|
112
|
+
|
113
|
+
spawn_mongocryptd
|
114
|
+
response = @mongocryptd_client.database.command(cmd)
|
115
|
+
end
|
116
|
+
|
117
|
+
return response.first
|
118
|
+
end
|
119
|
+
|
120
|
+
# Get information about the AWS encryption key and feed it to the the
|
121
|
+
# KmsContext object
|
122
|
+
#
|
123
|
+
# @param [ Mongo::Crypt::KmsContext ] kms_context A KmsContext object
|
124
|
+
# corresponding to one AWS KMS data key. Contains information about
|
125
|
+
# the endpoint at which to establish a TLS connection and the message
|
126
|
+
# to send on that connection.
|
127
|
+
def feed_kms(kms_context)
|
128
|
+
with_ssl_socket(kms_context.endpoint) do |ssl_socket|
|
129
|
+
|
130
|
+
Timeout.timeout(SOCKET_TIMEOUT, Error::SocketTimeoutError,
|
131
|
+
'Socket write operation timed out'
|
132
|
+
) do
|
133
|
+
ssl_socket.syswrite(kms_context.message)
|
134
|
+
end
|
135
|
+
|
136
|
+
bytes_needed = kms_context.bytes_needed
|
137
|
+
while bytes_needed > 0 do
|
138
|
+
bytes = Timeout.timeout(SOCKET_TIMEOUT, Error::SocketTimeoutError,
|
139
|
+
'Socket read operation timed out'
|
140
|
+
) do
|
141
|
+
ssl_socket.sysread(bytes_needed)
|
142
|
+
end
|
143
|
+
|
144
|
+
kms_context.feed(bytes)
|
145
|
+
bytes_needed = kms_context.bytes_needed
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
private
|
151
|
+
|
152
|
+
def validate_key_vault_client!(key_vault_client)
|
153
|
+
unless key_vault_client
|
154
|
+
raise ArgumentError.new('The :key_vault_client option cannot be nil')
|
155
|
+
end
|
156
|
+
|
157
|
+
unless key_vault_client.is_a?(Client)
|
158
|
+
raise ArgumentError.new(
|
159
|
+
'The :key_vault_client option must be an instance of Mongo::Client'
|
160
|
+
)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
def validate_key_vault_namespace!(key_vault_namespace)
|
165
|
+
unless key_vault_namespace
|
166
|
+
raise ArgumentError.new('The :key_vault_namespace option cannot be nil')
|
167
|
+
end
|
168
|
+
|
169
|
+
unless key_vault_namespace.split('.').length == 2
|
170
|
+
raise ArgumentError.new(
|
171
|
+
"#{key_vault_namespace} is an invalid key vault namespace." +
|
172
|
+
"The :key_vault_namespace option must be in the format database.collection"
|
173
|
+
)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
# Use the provided key vault client and namespace to construct a
|
178
|
+
# Mongo::Collection object representing the key vault collection.
|
179
|
+
def key_vault_collection
|
180
|
+
@key_vault_collection ||= @key_vault_client.with(
|
181
|
+
database: @key_vault_db_name,
|
182
|
+
read_concern: { level: :majority }
|
183
|
+
)[@key_vault_collection_name]
|
184
|
+
end
|
185
|
+
|
186
|
+
# Spawn a new mongocryptd process using the mongocryptd_spawn_path
|
187
|
+
# and mongocryptd_spawn_args passed in through the extra auto
|
188
|
+
# encrypt options. Stdout and Stderr of this new process are written
|
189
|
+
# to /dev/null.
|
190
|
+
#
|
191
|
+
# @note To capture the mongocryptd logs, add "--logpath=/path/to/logs"
|
192
|
+
# to auto_encryption_options -> extra_options -> mongocrpytd_spawn_args
|
193
|
+
#
|
194
|
+
# @return [ Integer ] The process id of the spawned process
|
195
|
+
#
|
196
|
+
# @raise [ ArgumentError ] Raises an exception if no encryption options
|
197
|
+
# have been provided
|
198
|
+
def spawn_mongocryptd
|
199
|
+
mongocryptd_spawn_args = @options[:mongocryptd_spawn_args]
|
200
|
+
mongocryptd_spawn_path = @options[:mongocryptd_spawn_path]
|
201
|
+
|
202
|
+
unless mongocryptd_spawn_path
|
203
|
+
raise ArgumentError.new(
|
204
|
+
'Cannot spawn mongocryptd process when no ' +
|
205
|
+
':mongocryptd_spawn_path option is provided'
|
206
|
+
)
|
207
|
+
end
|
208
|
+
|
209
|
+
if mongocryptd_spawn_path.nil? ||
|
210
|
+
mongocryptd_spawn_args.nil? || mongocryptd_spawn_args.empty?
|
211
|
+
then
|
212
|
+
raise ArgumentError.new(
|
213
|
+
'Cannot spawn mongocryptd process when no :mongocryptd_spawn_args ' +
|
214
|
+
'option is provided. To start mongocryptd without arguments, pass ' +
|
215
|
+
'"--" for :mongocryptd_spawn_args'
|
216
|
+
)
|
217
|
+
end
|
218
|
+
|
219
|
+
begin
|
220
|
+
Process.spawn(
|
221
|
+
mongocryptd_spawn_path,
|
222
|
+
*mongocryptd_spawn_args,
|
223
|
+
[:out, :err]=>'/dev/null'
|
224
|
+
)
|
225
|
+
rescue Errno::ENOENT => e
|
226
|
+
raise Error::MongocryptdSpawnError.new(
|
227
|
+
"Failed to spawn mongocryptd at the path \"#{mongocryptd_spawn_path}\" " +
|
228
|
+
"with arguments #{mongocryptd_spawn_args}. Received error " +
|
229
|
+
"#{e.class}: \"#{e.message}\""
|
230
|
+
)
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
# Provide an SSL socket to be used for KMS calls in a block API
|
235
|
+
#
|
236
|
+
# @param [ String ] endpoint The URI at which to connect the SSL socket
|
237
|
+
# @param [ Proc ] block The block to execute
|
238
|
+
#
|
239
|
+
# @raise [ Mongo::Error::KmsError ] If the socket times out or raises
|
240
|
+
# an exception
|
241
|
+
#
|
242
|
+
# @note The socket is always closed when the provided block has finished
|
243
|
+
# executing
|
244
|
+
def with_ssl_socket(endpoint)
|
245
|
+
host, port = endpoint.split(':')
|
246
|
+
port ||= 443 # Default port for AWS KMS API
|
247
|
+
|
248
|
+
begin
|
249
|
+
# Create TCPSocket and set nodelay option
|
250
|
+
tcp_socket = TCPSocket.open(host, port)
|
251
|
+
tcp_socket.setsockopt(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, 1)
|
252
|
+
|
253
|
+
ssl_socket = OpenSSL::SSL::SSLSocket.new(tcp_socket)
|
254
|
+
ssl_socket.sync_close = true # tcp_socket will be closed when ssl_socket is closed
|
255
|
+
ssl_socket.hostname = "#{host}:#{port}" # perform SNI
|
256
|
+
|
257
|
+
Timeout.timeout(
|
258
|
+
SOCKET_TIMEOUT,
|
259
|
+
Error::SocketTimeoutError,
|
260
|
+
'Socket connection timed out'
|
261
|
+
) do
|
262
|
+
ssl_socket.connect
|
263
|
+
end
|
264
|
+
|
265
|
+
yield(ssl_socket)
|
266
|
+
rescue => e
|
267
|
+
raise Error::KmsError, "Error decrypting data key. #{e.class}: #{e.message}"
|
268
|
+
ensure
|
269
|
+
# If there is an error during socket creation, the
|
270
|
+
# ssl_socket object won't exist in this scope and this line will
|
271
|
+
# raise an exception
|
272
|
+
Timeout.timeout(
|
273
|
+
SOCKET_TIMEOUT,
|
274
|
+
Error::SocketTimeoutError,
|
275
|
+
'Socket close timed out'
|
276
|
+
) do
|
277
|
+
ssl_socket.sysclose rescue nil
|
278
|
+
end
|
279
|
+
end
|
280
|
+
end
|
281
|
+
end
|
282
|
+
end
|
283
|
+
end
|